package com.bioxx.tfc2.world; import java.util.ArrayList; import java.util.Random; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.Teleporter; import net.minecraft.world.WorldServer; import com.bioxx.jmapgen.IslandMap; import com.bioxx.jmapgen.Point; import com.bioxx.jmapgen.Spline3D; import com.bioxx.jmapgen.attributes.Attribute; import com.bioxx.jmapgen.attributes.PortalAttribute; import com.bioxx.jmapgen.graph.Center; import com.bioxx.tfc2.Core; import com.bioxx.tfc2.TFCBlocks; import com.bioxx.tfc2.api.types.PortalEnumType; import com.bioxx.tfc2.api.util.Helper; import com.bioxx.tfc2.blocks.BlockPortal; import com.bioxx.tfc2.world.generators.WorldGenPortals; import it.unimi.dsi.fastutil.objects.ObjectIterator; public class TeleporterPaths extends Teleporter { public TeleporterPaths(WorldServer worldIn) { super(worldIn); } @Override /** * Finds or creates a portal and places the entity in the correct location * Note: The entity has already had its pos scaled for the scaling factor of this dimension. The coords * will need to unscaled when finding the island map <-Remove me later */ public void placeInPortal(Entity entity, float yaw) { //First check if we're teleporting back into the overworld if (this.worldServerInstance.provider.getDimension() != 0) { if (!this.placeInExistingPortal(entity, yaw)) { this.makePortal(entity); makePath(entity); this.placeInExistingPortal(entity, yaw); } } else { int playerX = MathHelper.floor_double(entity.posX); int playerZ = MathHelper.floor_double(entity.posZ); IslandMap islandMap = WorldGen.getInstance().getIslandMap(playerX >> 12, playerZ >> 12); Center closest = islandMap.getClosestCenter(new Point(playerX % 4096,playerZ % 4096)); //Sometimes due to the world scaling, we might find the closest center is actually a neighbor of the portal hex closest = this.getPortalNeighbor(closest); BlockPos pos = new BlockPos((playerX >> 12)*4096+closest.point.x, 64+islandMap.convertHeightToMC(closest.getElevation()), (playerZ >> 12)*4096+closest.point.y); //Find portal pos = this.findPortal(pos); PortalAttribute attr = (PortalAttribute) closest.getAttribute(Attribute.Portal); if(this.checkRoomForPlayer(pos.north())) pos = pos.north(); else if(this.checkRoomForPlayer(pos.south())) pos = pos.south(); else if(this.checkRoomForPlayer(pos.east())) pos = pos.east(); else if(this.checkRoomForPlayer(pos.west())) pos = pos.west(); entity.setLocationAndAngles(pos.getX()+0.5, pos.getY()+0.5, pos.getZ()+0.5, entity.rotationYaw+0.5f, entity.rotationPitch); } } private BlockPos findPortal(BlockPos pos) { IBlockState state; for(int x = -30; x < 31; x++) { for(int z = -30; z < 31; z++) { for(int y = -20; y < 20; y++) { state = this.worldServerInstance.getBlockState(pos.add(x, y, z)); if(state.getBlock() == TFCBlocks.Portal && (Boolean)state.getValue(BlockPortal.CENTER) == true) { if(this.worldServerInstance.getBlockState(pos.add(x, y, z).down()).getBlock() == TFCBlocks.Portal) return pos.add(x, y, z).down(); else return pos.add(x, y, z); } } } } return BlockPos.ORIGIN; } @Override public boolean placeInExistingPortal(Entity entityIn, float rotationYaw) { boolean flag = true; int playerX = MathHelper.floor_double(entityIn.posX); int playerZ = MathHelper.floor_double(entityIn.posZ); boolean shouldAddPortalPosition = true; boolean foundPortal = false; BlockPos object = BlockPos.ORIGIN; long k = ChunkPos.asLong(playerX, playerZ); IslandMap islandMap = Core.getMapForWorld(worldServerInstance, entityIn.getPosition()); Center closest = islandMap.getClosestCenter(new Point((playerX*8) % 4096,(playerZ*8) % 4096)); //Check if we already have a portal position cached here if (this.destinationCoordinateCache.containsKey(k)) { Teleporter.PortalPosition portalposition = (Teleporter.PortalPosition)this.destinationCoordinateCache.get(k); object = portalposition; portalposition.lastUpdateTime = this.worldServerInstance.getTotalWorldTime(); shouldAddPortalPosition = false; } else //If not then we do a simple search for the closest portal block { BlockPos blockpos4 = new BlockPos(entityIn); object = this.findPortal(blockpos4); } //If we found a portal location then we need to move the player to it if (object != BlockPos.ORIGIN) { if (shouldAddPortalPosition) { this.destinationCoordinateCache.put(k, new Teleporter.PortalPosition((BlockPos)object, this.worldServerInstance.getTotalWorldTime())); //this.destinationCoordinateKeys.add(Long.valueOf(k)); } EnumFacing enumfacing = null; BlockPos pos = object; PortalAttribute attr = (PortalAttribute) closest.getAttribute(Attribute.Portal); if(this.checkRoomForPlayer(pos.north())) pos = pos.north(); else if(this.checkRoomForPlayer(pos.south())) pos = pos.south(); else if(this.checkRoomForPlayer(pos.east())) pos = pos.east(); else if(this.checkRoomForPlayer(pos.west())) pos = pos.west(); entityIn.setLocationAndAngles(pos.getX()+0.5, pos.getY()+0.5, pos.getZ()+0.5, entityIn.rotationYaw+0.5f, entityIn.rotationPitch); return true; } else { return false; } } private boolean checkRoomForPlayer(BlockPos pos) { return this.worldServerInstance.isAirBlock(pos) || this.worldServerInstance.isAirBlock(pos.up()); } @Override public boolean makePortal(Entity entityIn) { int playerX = MathHelper.floor_double(entityIn.posX); int playerZ = MathHelper.floor_double(entityIn.posZ); IslandMap islandMap = WorldGen.getInstance().getIslandMap(((playerX*8) >> 12), ((playerZ*8) >> 12)); Center closest = islandMap.getClosestCenter(new Point((playerX*8) % 4096,(playerZ*8) % 4096)); //Sometimes due to the world scaling, we might find the closest center is actually a neighbor of the portal hex closest = this.getPortalNeighbor(closest); BlockPos portalPos = new BlockPos(entityIn); WorldGenPortals.BuildPortalSchem(worldServerInstance, closest, portalPos, islandMap, true); return true; } public boolean makePath(Entity entityIn) { int playerX = MathHelper.floor_double(entityIn.posX); int playerZ = MathHelper.floor_double(entityIn.posZ); int xM = ((playerX*8) >> 12); int zM = ((playerZ*8) >> 12); int xI = xM * 4096; int zI = zM * 4096; int xP = (playerX*8) % 4096; int zP = (playerZ*8) % 4096; IslandMap islandMap = WorldGen.getInstance().getIslandMap(xM, zM); Center closest = islandMap.getClosestCenter(new Point(xP,zP)); //Sometimes due to the world scaling, we might find the closest center is actually a neighbor of the portal hex closest = this.getPortalNeighbor(closest); BlockPos portalPos = new BlockPos(entityIn); PortalAttribute startAttr = (PortalAttribute) closest.getAttribute(Attribute.Portal); int destX = Helper.getXCoord(startAttr.destMapID); int destZ = Helper.getYCoord(startAttr.destMapID); IslandMap destMap = WorldGen.getInstance().getIslandMap(destX, destZ); Center dest = destMap.getPortalForFacing(startAttr.direction.getOpposite()); PortalAttribute endAttr = (PortalAttribute) dest.getAttribute(Attribute.Portal); double factor = 1/this.worldServerInstance.provider.getMovementFactor(); BlockPos start = closest.point.toBlockPos().add(xI, 64+islandMap.convertHeightToMC(closest.getElevation()), zI); start = new BlockPos(start.getX() * factor, start.getY()-1, start.getZ() * factor); BlockPos end = dest.point.toBlockPos().add(destX * 4096, 64+destMap.convertHeightToMC(dest.getElevation()), destZ * 4096); end = new BlockPos(end.getX() * factor, end.getY()-1, end.getZ() * factor); //Create the spline if it does not exist if(startAttr.getSpline() == null) { //Copy the spline from the other side if it exists for some reason if(endAttr.getSpline() != null) { startAttr.setPath(endAttr.getPath()); } else//Otherwise create new { Random r = new Random(closest.index + dest.index); ArrayList<BlockPos> list = new ArrayList<BlockPos>(); list.add(start); list.add(end); Spline3D spline = new Spline3D(list); list = new ArrayList<BlockPos>(); list.add(start); double loc = 1D / 7D; for(int i = 1; i < 6; i++) { BlockPos pos = spline.getPoint((double)i*loc); pos = pos.add(-30+r.nextInt(61), -5+r.nextInt(11), -30+r.nextInt(61)); list.add(pos); } list.add(end); startAttr.setPath(list); endAttr.setPath(list); } } if(destMap.getIslandData().getPortalState(endAttr.direction) == PortalEnumType.Disabled) destMap.getIslandData().enablePortal(endAttr.direction); WorldGenPortals.BuildPath(worldServerInstance, start, end, startAttr.getSpline()); WorldGenPortals.BuildPortalSchem(worldServerInstance, dest, end, destMap, true); return true; } public Center getPortalNeighbor(Center closest) { if(!closest.hasAttribute(Attribute.Portal)) { for(Center c : closest.neighbors) { if(c.hasAttribute(Attribute.Portal)) { return c; } } } return closest; } /** * called periodically to remove out-of-date portal locations from the cache list. Argument par1 is a * WorldServer.getTotalWorldTime() value. */ @Override public void removeStalePortalLocations(long worldTime) { if (worldTime % 100L == 0L) { long i = worldTime - 600L; ObjectIterator<Teleporter.PortalPosition> objectiterator = this.destinationCoordinateCache.values().iterator(); while (objectiterator.hasNext()) { Teleporter.PortalPosition teleporter$portalposition = (Teleporter.PortalPosition)objectiterator.next(); if (teleporter$portalposition == null || teleporter$portalposition.lastUpdateTime < i) { objectiterator.remove(); } } } } }