001package net.minecraft.world; 002 003import java.util.ArrayList; 004import java.util.Iterator; 005import java.util.List; 006import java.util.Random; 007import net.minecraft.block.Block; 008import net.minecraft.entity.Entity; 009import net.minecraft.util.Direction; 010import net.minecraft.util.LongHashMap; 011import net.minecraft.util.MathHelper; 012 013public class Teleporter 014{ 015 private final WorldServer worldServerInstance; 016 017 /** A private Random() function in Teleporter */ 018 private final Random random; 019 private final LongHashMap field_85191_c = new LongHashMap(); 020 private final List field_85190_d = new ArrayList(); 021 022 public Teleporter(WorldServer par1WorldServer) 023 { 024 this.worldServerInstance = par1WorldServer; 025 this.random = new Random(par1WorldServer.getSeed()); 026 } 027 028 /** 029 * Place an entity in a nearby portal, creating one if necessary. 030 */ 031 public void placeInPortal(Entity par1Entity, double par2, double par4, double par6, float par8) 032 { 033 if (this.worldServerInstance.provider.dimensionId != 1) 034 { 035 if (!this.placeInExistingPortal(par1Entity, par2, par4, par6, par8)) 036 { 037 this.makePortal(par1Entity); 038 this.placeInExistingPortal(par1Entity, par2, par4, par6, par8); 039 } 040 } 041 else 042 { 043 int i = MathHelper.floor_double(par1Entity.posX); 044 int j = MathHelper.floor_double(par1Entity.posY) - 1; 045 int k = MathHelper.floor_double(par1Entity.posZ); 046 byte b0 = 1; 047 byte b1 = 0; 048 049 for (int l = -2; l <= 2; ++l) 050 { 051 for (int i1 = -2; i1 <= 2; ++i1) 052 { 053 for (int j1 = -1; j1 < 3; ++j1) 054 { 055 int k1 = i + i1 * b0 + l * b1; 056 int l1 = j + j1; 057 int i2 = k + i1 * b1 - l * b0; 058 boolean flag = j1 < 0; 059 this.worldServerInstance.func_94575_c(k1, l1, i2, flag ? Block.obsidian.blockID : 0); 060 } 061 } 062 } 063 064 par1Entity.setLocationAndAngles((double)i, (double)j, (double)k, par1Entity.rotationYaw, 0.0F); 065 par1Entity.motionX = par1Entity.motionY = par1Entity.motionZ = 0.0D; 066 } 067 } 068 069 /** 070 * Place an entity in a nearby portal which already exists. 071 */ 072 public boolean placeInExistingPortal(Entity par1Entity, double par2, double par4, double par6, float par8) 073 { 074 short short1 = 128; 075 double d3 = -1.0D; 076 int i = 0; 077 int j = 0; 078 int k = 0; 079 int l = MathHelper.floor_double(par1Entity.posX); 080 int i1 = MathHelper.floor_double(par1Entity.posZ); 081 long j1 = ChunkCoordIntPair.chunkXZ2Int(l, i1); 082 boolean flag = true; 083 double d4; 084 int k1; 085 086 if (this.field_85191_c.containsItem(j1)) 087 { 088 PortalPosition portalposition = (PortalPosition)this.field_85191_c.getValueByKey(j1); 089 d3 = 0.0D; 090 i = portalposition.posX; 091 j = portalposition.posY; 092 k = portalposition.posZ; 093 portalposition.field_85087_d = this.worldServerInstance.getTotalWorldTime(); 094 flag = false; 095 } 096 else 097 { 098 for (k1 = l - short1; k1 <= l + short1; ++k1) 099 { 100 double d5 = (double)k1 + 0.5D - par1Entity.posX; 101 102 for (int l1 = i1 - short1; l1 <= i1 + short1; ++l1) 103 { 104 double d6 = (double)l1 + 0.5D - par1Entity.posZ; 105 106 for (int i2 = this.worldServerInstance.getActualHeight() - 1; i2 >= 0; --i2) 107 { 108 if (this.worldServerInstance.getBlockId(k1, i2, l1) == Block.portal.blockID) 109 { 110 while (this.worldServerInstance.getBlockId(k1, i2 - 1, l1) == Block.portal.blockID) 111 { 112 --i2; 113 } 114 115 d4 = (double)i2 + 0.5D - par1Entity.posY; 116 double d7 = d5 * d5 + d4 * d4 + d6 * d6; 117 118 if (d3 < 0.0D || d7 < d3) 119 { 120 d3 = d7; 121 i = k1; 122 j = i2; 123 k = l1; 124 } 125 } 126 } 127 } 128 } 129 } 130 131 if (d3 >= 0.0D) 132 { 133 if (flag) 134 { 135 this.field_85191_c.add(j1, new PortalPosition(this, i, j, k, this.worldServerInstance.getTotalWorldTime())); 136 this.field_85190_d.add(Long.valueOf(j1)); 137 } 138 139 double d8 = (double)i + 0.5D; 140 double d9 = (double)j + 0.5D; 141 d4 = (double)k + 0.5D; 142 int j2 = -1; 143 144 if (this.worldServerInstance.getBlockId(i - 1, j, k) == Block.portal.blockID) 145 { 146 j2 = 2; 147 } 148 149 if (this.worldServerInstance.getBlockId(i + 1, j, k) == Block.portal.blockID) 150 { 151 j2 = 0; 152 } 153 154 if (this.worldServerInstance.getBlockId(i, j, k - 1) == Block.portal.blockID) 155 { 156 j2 = 3; 157 } 158 159 if (this.worldServerInstance.getBlockId(i, j, k + 1) == Block.portal.blockID) 160 { 161 j2 = 1; 162 } 163 164 int k2 = par1Entity.func_82148_at(); 165 166 if (j2 > -1) 167 { 168 int l2 = Direction.field_71578_g[j2]; 169 int i3 = Direction.offsetX[j2]; 170 int j3 = Direction.offsetZ[j2]; 171 int k3 = Direction.offsetX[l2]; 172 int l3 = Direction.offsetZ[l2]; 173 boolean flag1 = !this.worldServerInstance.isAirBlock(i + i3 + k3, j, k + j3 + l3) || !this.worldServerInstance.isAirBlock(i + i3 + k3, j + 1, k + j3 + l3); 174 boolean flag2 = !this.worldServerInstance.isAirBlock(i + i3, j, k + j3) || !this.worldServerInstance.isAirBlock(i + i3, j + 1, k + j3); 175 176 if (flag1 && flag2) 177 { 178 j2 = Direction.footInvisibleFaceRemap[j2]; 179 l2 = Direction.footInvisibleFaceRemap[l2]; 180 i3 = Direction.offsetX[j2]; 181 j3 = Direction.offsetZ[j2]; 182 k3 = Direction.offsetX[l2]; 183 l3 = Direction.offsetZ[l2]; 184 k1 = i - k3; 185 d8 -= (double)k3; 186 int i4 = k - l3; 187 d4 -= (double)l3; 188 flag1 = !this.worldServerInstance.isAirBlock(k1 + i3 + k3, j, i4 + j3 + l3) || !this.worldServerInstance.isAirBlock(k1 + i3 + k3, j + 1, i4 + j3 + l3); 189 flag2 = !this.worldServerInstance.isAirBlock(k1 + i3, j, i4 + j3) || !this.worldServerInstance.isAirBlock(k1 + i3, j + 1, i4 + j3); 190 } 191 192 float f1 = 0.5F; 193 float f2 = 0.5F; 194 195 if (!flag1 && flag2) 196 { 197 f1 = 1.0F; 198 } 199 else if (flag1 && !flag2) 200 { 201 f1 = 0.0F; 202 } 203 else if (flag1 && flag2) 204 { 205 f2 = 0.0F; 206 } 207 208 d8 += (double)((float)k3 * f1 + f2 * (float)i3); 209 d4 += (double)((float)l3 * f1 + f2 * (float)j3); 210 float f3 = 0.0F; 211 float f4 = 0.0F; 212 float f5 = 0.0F; 213 float f6 = 0.0F; 214 215 if (j2 == k2) 216 { 217 f3 = 1.0F; 218 f4 = 1.0F; 219 } 220 else if (j2 == Direction.footInvisibleFaceRemap[k2]) 221 { 222 f3 = -1.0F; 223 f4 = -1.0F; 224 } 225 else if (j2 == Direction.enderEyeMetaToDirection[k2]) 226 { 227 f5 = 1.0F; 228 f6 = -1.0F; 229 } 230 else 231 { 232 f5 = -1.0F; 233 f6 = 1.0F; 234 } 235 236 double d10 = par1Entity.motionX; 237 double d11 = par1Entity.motionZ; 238 par1Entity.motionX = d10 * (double)f3 + d11 * (double)f6; 239 par1Entity.motionZ = d10 * (double)f5 + d11 * (double)f4; 240 par1Entity.rotationYaw = par8 - (float)(k2 * 90) + (float)(j2 * 90); 241 } 242 else 243 { 244 par1Entity.motionX = par1Entity.motionY = par1Entity.motionZ = 0.0D; 245 } 246 247 par1Entity.setLocationAndAngles(d8, d9, d4, par1Entity.rotationYaw, par1Entity.rotationPitch); 248 return true; 249 } 250 else 251 { 252 return false; 253 } 254 } 255 256 public boolean makePortal(Entity par1Entity) 257 { 258 byte b0 = 16; 259 double d0 = -1.0D; 260 int i = MathHelper.floor_double(par1Entity.posX); 261 int j = MathHelper.floor_double(par1Entity.posY); 262 int k = MathHelper.floor_double(par1Entity.posZ); 263 int l = i; 264 int i1 = j; 265 int j1 = k; 266 int k1 = 0; 267 int l1 = this.random.nextInt(4); 268 int i2; 269 double d1; 270 double d2; 271 int j2; 272 int k2; 273 int l2; 274 int i3; 275 int j3; 276 int k3; 277 int l3; 278 int i4; 279 int j4; 280 int k4; 281 double d3; 282 double d4; 283 284 for (i2 = i - b0; i2 <= i + b0; ++i2) 285 { 286 d1 = (double)i2 + 0.5D - par1Entity.posX; 287 288 for (j2 = k - b0; j2 <= k + b0; ++j2) 289 { 290 d2 = (double)j2 + 0.5D - par1Entity.posZ; 291 label274: 292 293 for (k2 = this.worldServerInstance.getActualHeight() - 1; k2 >= 0; --k2) 294 { 295 if (this.worldServerInstance.isAirBlock(i2, k2, j2)) 296 { 297 while (k2 > 0 && this.worldServerInstance.isAirBlock(i2, k2 - 1, j2)) 298 { 299 --k2; 300 } 301 302 for (i3 = l1; i3 < l1 + 4; ++i3) 303 { 304 l2 = i3 % 2; 305 k3 = 1 - l2; 306 307 if (i3 % 4 >= 2) 308 { 309 l2 = -l2; 310 k3 = -k3; 311 } 312 313 for (j3 = 0; j3 < 3; ++j3) 314 { 315 for (i4 = 0; i4 < 4; ++i4) 316 { 317 for (l3 = -1; l3 < 4; ++l3) 318 { 319 k4 = i2 + (i4 - 1) * l2 + j3 * k3; 320 j4 = k2 + l3; 321 int l4 = j2 + (i4 - 1) * k3 - j3 * l2; 322 323 if (l3 < 0 && !this.worldServerInstance.getBlockMaterial(k4, j4, l4).isSolid() || l3 >= 0 && !this.worldServerInstance.isAirBlock(k4, j4, l4)) 324 { 325 continue label274; 326 } 327 } 328 } 329 } 330 331 d4 = (double)k2 + 0.5D - par1Entity.posY; 332 d3 = d1 * d1 + d4 * d4 + d2 * d2; 333 334 if (d0 < 0.0D || d3 < d0) 335 { 336 d0 = d3; 337 l = i2; 338 i1 = k2; 339 j1 = j2; 340 k1 = i3 % 4; 341 } 342 } 343 } 344 } 345 } 346 } 347 348 if (d0 < 0.0D) 349 { 350 for (i2 = i - b0; i2 <= i + b0; ++i2) 351 { 352 d1 = (double)i2 + 0.5D - par1Entity.posX; 353 354 for (j2 = k - b0; j2 <= k + b0; ++j2) 355 { 356 d2 = (double)j2 + 0.5D - par1Entity.posZ; 357 label222: 358 359 for (k2 = this.worldServerInstance.getActualHeight() - 1; k2 >= 0; --k2) 360 { 361 if (this.worldServerInstance.isAirBlock(i2, k2, j2)) 362 { 363 while (k2 > 0 && this.worldServerInstance.isAirBlock(i2, k2 - 1, j2)) 364 { 365 --k2; 366 } 367 368 for (i3 = l1; i3 < l1 + 2; ++i3) 369 { 370 l2 = i3 % 2; 371 k3 = 1 - l2; 372 373 for (j3 = 0; j3 < 4; ++j3) 374 { 375 for (i4 = -1; i4 < 4; ++i4) 376 { 377 l3 = i2 + (j3 - 1) * l2; 378 k4 = k2 + i4; 379 j4 = j2 + (j3 - 1) * k3; 380 381 if (i4 < 0 && !this.worldServerInstance.getBlockMaterial(l3, k4, j4).isSolid() || i4 >= 0 && !this.worldServerInstance.isAirBlock(l3, k4, j4)) 382 { 383 continue label222; 384 } 385 } 386 } 387 388 d4 = (double)k2 + 0.5D - par1Entity.posY; 389 d3 = d1 * d1 + d4 * d4 + d2 * d2; 390 391 if (d0 < 0.0D || d3 < d0) 392 { 393 d0 = d3; 394 l = i2; 395 i1 = k2; 396 j1 = j2; 397 k1 = i3 % 2; 398 } 399 } 400 } 401 } 402 } 403 } 404 } 405 406 int i5 = l; 407 int j5 = i1; 408 j2 = j1; 409 int k5 = k1 % 2; 410 int l5 = 1 - k5; 411 412 if (k1 % 4 >= 2) 413 { 414 k5 = -k5; 415 l5 = -l5; 416 } 417 418 boolean flag; 419 420 if (d0 < 0.0D) 421 { 422 if (i1 < 70) 423 { 424 i1 = 70; 425 } 426 427 if (i1 > this.worldServerInstance.getActualHeight() - 10) 428 { 429 i1 = this.worldServerInstance.getActualHeight() - 10; 430 } 431 432 j5 = i1; 433 434 for (k2 = -1; k2 <= 1; ++k2) 435 { 436 for (i3 = 1; i3 < 3; ++i3) 437 { 438 for (l2 = -1; l2 < 3; ++l2) 439 { 440 k3 = i5 + (i3 - 1) * k5 + k2 * l5; 441 j3 = j5 + l2; 442 i4 = j2 + (i3 - 1) * l5 - k2 * k5; 443 flag = l2 < 0; 444 this.worldServerInstance.func_94575_c(k3, j3, i4, flag ? Block.obsidian.blockID : 0); 445 } 446 } 447 } 448 } 449 450 for (k2 = 0; k2 < 4; ++k2) 451 { 452 for (i3 = 0; i3 < 4; ++i3) 453 { 454 for (l2 = -1; l2 < 4; ++l2) 455 { 456 k3 = i5 + (i3 - 1) * k5; 457 j3 = j5 + l2; 458 i4 = j2 + (i3 - 1) * l5; 459 flag = i3 == 0 || i3 == 3 || l2 == -1 || l2 == 3; 460 this.worldServerInstance.setBlockAndMetadataWithNotify(k3, j3, i4, flag ? Block.obsidian.blockID : Block.portal.blockID, 0, 2); 461 } 462 } 463 464 for (i3 = 0; i3 < 4; ++i3) 465 { 466 for (l2 = -1; l2 < 4; ++l2) 467 { 468 k3 = i5 + (i3 - 1) * k5; 469 j3 = j5 + l2; 470 i4 = j2 + (i3 - 1) * l5; 471 this.worldServerInstance.notifyBlocksOfNeighborChange(k3, j3, i4, this.worldServerInstance.getBlockId(k3, j3, i4)); 472 } 473 } 474 } 475 476 return true; 477 } 478 479 public void func_85189_a(long par1) 480 { 481 if (par1 % 100L == 0L) 482 { 483 Iterator iterator = this.field_85190_d.iterator(); 484 long j = par1 - 600L; 485 486 while (iterator.hasNext()) 487 { 488 Long olong = (Long)iterator.next(); 489 PortalPosition portalposition = (PortalPosition)this.field_85191_c.getValueByKey(olong.longValue()); 490 491 if (portalposition == null || portalposition.field_85087_d < j) 492 { 493 iterator.remove(); 494 this.field_85191_c.remove(olong.longValue()); 495 } 496 } 497 } 498 } 499}