001    package net.minecraft.world;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    import java.util.Random;
007    import net.minecraft.block.Block;
008    import net.minecraft.entity.Entity;
009    import net.minecraft.util.Direction;
010    import net.minecraft.util.LongHashMap;
011    import net.minecraft.util.MathHelper;
012    
013    public class Teleporter
014    {
015        private final WorldServer field_85192_a;
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.field_85192_a = 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.field_85192_a.provider.dimensionId != 1)
034            {
035                if (!this.placeInExistingPortal(par1Entity, par2, par4, par6, par8))
036                {
037                    this.func_85188_a(par1Entity);
038                    this.placeInExistingPortal(par1Entity, par2, par4, par6, par8);
039                }
040            }
041            else
042            {
043                int var9 = MathHelper.floor_double(par1Entity.posX);
044                int var10 = MathHelper.floor_double(par1Entity.posY) - 1;
045                int var11 = MathHelper.floor_double(par1Entity.posZ);
046                byte var12 = 1;
047                byte var13 = 0;
048    
049                for (int var14 = -2; var14 <= 2; ++var14)
050                {
051                    for (int var15 = -2; var15 <= 2; ++var15)
052                    {
053                        for (int var16 = -1; var16 < 3; ++var16)
054                        {
055                            int var17 = var9 + var15 * var12 + var14 * var13;
056                            int var18 = var10 + var16;
057                            int var19 = var11 + var15 * var13 - var14 * var12;
058                            boolean var20 = var16 < 0;
059                            this.field_85192_a.setBlockWithNotify(var17, var18, var19, var20 ? Block.obsidian.blockID : 0);
060                        }
061                    }
062                }
063    
064                par1Entity.setLocationAndAngles((double)var9, (double)var10, (double)var11, 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 var9 = 128;
075            double var10 = -1.0D;
076            int var12 = 0;
077            int var13 = 0;
078            int var14 = 0;
079            int var15 = MathHelper.floor_double(par1Entity.posX);
080            int var16 = MathHelper.floor_double(par1Entity.posZ);
081            long var17 = ChunkCoordIntPair.chunkXZ2Int(var15, var16);
082            boolean var19 = true;
083            double var27;
084            int var48;
085    
086            if (this.field_85191_c.containsItem(var17))
087            {
088                PortalPosition var20 = (PortalPosition)this.field_85191_c.getValueByKey(var17);
089                var10 = 0.0D;
090                var12 = var20.posX;
091                var13 = var20.posY;
092                var14 = var20.posZ;
093                var20.field_85087_d = this.field_85192_a.getTotalWorldTime();
094                var19 = false;
095            }
096            else
097            {
098                for (var48 = var15 - var9; var48 <= var15 + var9; ++var48)
099                {
100                    double var21 = (double)var48 + 0.5D - par1Entity.posX;
101    
102                    for (int var23 = var16 - var9; var23 <= var16 + var9; ++var23)
103                    {
104                        double var24 = (double)var23 + 0.5D - par1Entity.posZ;
105    
106                        for (int var26 = this.field_85192_a.getActualHeight() - 1; var26 >= 0; --var26)
107                        {
108                            if (this.field_85192_a.getBlockId(var48, var26, var23) == Block.portal.blockID)
109                            {
110                                while (this.field_85192_a.getBlockId(var48, var26 - 1, var23) == Block.portal.blockID)
111                                {
112                                    --var26;
113                                }
114    
115                                var27 = (double)var26 + 0.5D - par1Entity.posY;
116                                double var29 = var21 * var21 + var27 * var27 + var24 * var24;
117    
118                                if (var10 < 0.0D || var29 < var10)
119                                {
120                                    var10 = var29;
121                                    var12 = var48;
122                                    var13 = var26;
123                                    var14 = var23;
124                                }
125                            }
126                        }
127                    }
128                }
129            }
130    
131            if (var10 >= 0.0D)
132            {
133                if (var19)
134                {
135                    this.field_85191_c.add(var17, new PortalPosition(this, var12, var13, var14, this.field_85192_a.getTotalWorldTime()));
136                    this.field_85190_d.add(Long.valueOf(var17));
137                }
138    
139                double var49 = (double)var12 + 0.5D;
140                double var25 = (double)var13 + 0.5D;
141                var27 = (double)var14 + 0.5D;
142                int var50 = -1;
143    
144                if (this.field_85192_a.getBlockId(var12 - 1, var13, var14) == Block.portal.blockID)
145                {
146                    var50 = 2;
147                }
148    
149                if (this.field_85192_a.getBlockId(var12 + 1, var13, var14) == Block.portal.blockID)
150                {
151                    var50 = 0;
152                }
153    
154                if (this.field_85192_a.getBlockId(var12, var13, var14 - 1) == Block.portal.blockID)
155                {
156                    var50 = 3;
157                }
158    
159                if (this.field_85192_a.getBlockId(var12, var13, var14 + 1) == Block.portal.blockID)
160                {
161                    var50 = 1;
162                }
163    
164                int var30 = par1Entity.func_82148_at();
165    
166                if (var50 > -1)
167                {
168                    int var31 = Direction.field_71578_g[var50];
169                    int var32 = Direction.offsetX[var50];
170                    int var33 = Direction.offsetZ[var50];
171                    int var34 = Direction.offsetX[var31];
172                    int var35 = Direction.offsetZ[var31];
173                    boolean var36 = !this.field_85192_a.isAirBlock(var12 + var32 + var34, var13, var14 + var33 + var35) || !this.field_85192_a.isAirBlock(var12 + var32 + var34, var13 + 1, var14 + var33 + var35);
174                    boolean var37 = !this.field_85192_a.isAirBlock(var12 + var32, var13, var14 + var33) || !this.field_85192_a.isAirBlock(var12 + var32, var13 + 1, var14 + var33);
175    
176                    if (var36 && var37)
177                    {
178                        var50 = Direction.footInvisibleFaceRemap[var50];
179                        var31 = Direction.footInvisibleFaceRemap[var31];
180                        var32 = Direction.offsetX[var50];
181                        var33 = Direction.offsetZ[var50];
182                        var34 = Direction.offsetX[var31];
183                        var35 = Direction.offsetZ[var31];
184                        var48 = var12 - var34;
185                        var49 -= (double)var34;
186                        int var22 = var14 - var35;
187                        var27 -= (double)var35;
188                        var36 = !this.field_85192_a.isAirBlock(var48 + var32 + var34, var13, var22 + var33 + var35) || !this.field_85192_a.isAirBlock(var48 + var32 + var34, var13 + 1, var22 + var33 + var35);
189                        var37 = !this.field_85192_a.isAirBlock(var48 + var32, var13, var22 + var33) || !this.field_85192_a.isAirBlock(var48 + var32, var13 + 1, var22 + var33);
190                    }
191    
192                    float var38 = 0.5F;
193                    float var39 = 0.5F;
194    
195                    if (!var36 && var37)
196                    {
197                        var38 = 1.0F;
198                    }
199                    else if (var36 && !var37)
200                    {
201                        var38 = 0.0F;
202                    }
203                    else if (var36 && var37)
204                    {
205                        var39 = 0.0F;
206                    }
207    
208                    var49 += (double)((float)var34 * var38 + var39 * (float)var32);
209                    var27 += (double)((float)var35 * var38 + var39 * (float)var33);
210                    float var40 = 0.0F;
211                    float var41 = 0.0F;
212                    float var42 = 0.0F;
213                    float var43 = 0.0F;
214    
215                    if (var50 == var30)
216                    {
217                        var40 = 1.0F;
218                        var41 = 1.0F;
219                    }
220                    else if (var50 == Direction.footInvisibleFaceRemap[var30])
221                    {
222                        var40 = -1.0F;
223                        var41 = -1.0F;
224                    }
225                    else if (var50 == Direction.enderEyeMetaToDirection[var30])
226                    {
227                        var42 = 1.0F;
228                        var43 = -1.0F;
229                    }
230                    else
231                    {
232                        var42 = -1.0F;
233                        var43 = 1.0F;
234                    }
235    
236                    double var44 = par1Entity.motionX;
237                    double var46 = par1Entity.motionZ;
238                    par1Entity.motionX = var44 * (double)var40 + var46 * (double)var43;
239                    par1Entity.motionZ = var44 * (double)var42 + var46 * (double)var41;
240                    par1Entity.rotationYaw = par8 - (float)(var30 * 90) + (float)(var50 * 90);
241                }
242                else
243                {
244                    par1Entity.motionX = par1Entity.motionY = par1Entity.motionZ = 0.0D;
245                }
246    
247                par1Entity.setLocationAndAngles(var49, var25, var27, par1Entity.rotationYaw, par1Entity.rotationPitch);
248                return true;
249            }
250            else
251            {
252                return false;
253            }
254        }
255    
256        public boolean func_85188_a(Entity par1Entity)
257        {
258            byte var2 = 16;
259            double var3 = -1.0D;
260            int var5 = MathHelper.floor_double(par1Entity.posX);
261            int var6 = MathHelper.floor_double(par1Entity.posY);
262            int var7 = MathHelper.floor_double(par1Entity.posZ);
263            int var8 = var5;
264            int var9 = var6;
265            int var10 = var7;
266            int var11 = 0;
267            int var12 = this.random.nextInt(4);
268            int var13;
269            double var14;
270            double var17;
271            int var16;
272            int var19;
273            int var21;
274            int var20;
275            int var23;
276            int var22;
277            int var25;
278            int var24;
279            int var27;
280            int var26;
281            double var31;
282            double var32;
283    
284            for (var13 = var5 - var2; var13 <= var5 + var2; ++var13)
285            {
286                var14 = (double)var13 + 0.5D - par1Entity.posX;
287    
288                for (var16 = var7 - var2; var16 <= var7 + var2; ++var16)
289                {
290                    var17 = (double)var16 + 0.5D - par1Entity.posZ;
291                    label274:
292    
293                    for (var19 = this.field_85192_a.getActualHeight() - 1; var19 >= 0; --var19)
294                    {
295                        if (this.field_85192_a.isAirBlock(var13, var19, var16))
296                        {
297                            while (var19 > 0 && this.field_85192_a.isAirBlock(var13, var19 - 1, var16))
298                            {
299                                --var19;
300                            }
301    
302                            for (var20 = var12; var20 < var12 + 4; ++var20)
303                            {
304                                var21 = var20 % 2;
305                                var22 = 1 - var21;
306    
307                                if (var20 % 4 >= 2)
308                                {
309                                    var21 = -var21;
310                                    var22 = -var22;
311                                }
312    
313                                for (var23 = 0; var23 < 3; ++var23)
314                                {
315                                    for (var24 = 0; var24 < 4; ++var24)
316                                    {
317                                        for (var25 = -1; var25 < 4; ++var25)
318                                        {
319                                            var26 = var13 + (var24 - 1) * var21 + var23 * var22;
320                                            var27 = var19 + var25;
321                                            int var28 = var16 + (var24 - 1) * var22 - var23 * var21;
322    
323                                            if (var25 < 0 && !this.field_85192_a.getBlockMaterial(var26, var27, var28).isSolid() || var25 >= 0 && !this.field_85192_a.isAirBlock(var26, var27, var28))
324                                            {
325                                                continue label274;
326                                            }
327                                        }
328                                    }
329                                }
330    
331                                var32 = (double)var19 + 0.5D - par1Entity.posY;
332                                var31 = var14 * var14 + var32 * var32 + var17 * var17;
333    
334                                if (var3 < 0.0D || var31 < var3)
335                                {
336                                    var3 = var31;
337                                    var8 = var13;
338                                    var9 = var19;
339                                    var10 = var16;
340                                    var11 = var20 % 4;
341                                }
342                            }
343                        }
344                    }
345                }
346            }
347    
348            if (var3 < 0.0D)
349            {
350                for (var13 = var5 - var2; var13 <= var5 + var2; ++var13)
351                {
352                    var14 = (double)var13 + 0.5D - par1Entity.posX;
353    
354                    for (var16 = var7 - var2; var16 <= var7 + var2; ++var16)
355                    {
356                        var17 = (double)var16 + 0.5D - par1Entity.posZ;
357                        label222:
358    
359                        for (var19 = this.field_85192_a.getActualHeight() - 1; var19 >= 0; --var19)
360                        {
361                            if (this.field_85192_a.isAirBlock(var13, var19, var16))
362                            {
363                                while (var19 > 0 && this.field_85192_a.isAirBlock(var13, var19 - 1, var16))
364                                {
365                                    --var19;
366                                }
367    
368                                for (var20 = var12; var20 < var12 + 2; ++var20)
369                                {
370                                    var21 = var20 % 2;
371                                    var22 = 1 - var21;
372    
373                                    for (var23 = 0; var23 < 4; ++var23)
374                                    {
375                                        for (var24 = -1; var24 < 4; ++var24)
376                                        {
377                                            var25 = var13 + (var23 - 1) * var21;
378                                            var26 = var19 + var24;
379                                            var27 = var16 + (var23 - 1) * var22;
380    
381                                            if (var24 < 0 && !this.field_85192_a.getBlockMaterial(var25, var26, var27).isSolid() || var24 >= 0 && !this.field_85192_a.isAirBlock(var25, var26, var27))
382                                            {
383                                                continue label222;
384                                            }
385                                        }
386                                    }
387    
388                                    var32 = (double)var19 + 0.5D - par1Entity.posY;
389                                    var31 = var14 * var14 + var32 * var32 + var17 * var17;
390    
391                                    if (var3 < 0.0D || var31 < var3)
392                                    {
393                                        var3 = var31;
394                                        var8 = var13;
395                                        var9 = var19;
396                                        var10 = var16;
397                                        var11 = var20 % 2;
398                                    }
399                                }
400                            }
401                        }
402                    }
403                }
404            }
405    
406            int var29 = var8;
407            int var15 = var9;
408            var16 = var10;
409            int var30 = var11 % 2;
410            int var18 = 1 - var30;
411    
412            if (var11 % 4 >= 2)
413            {
414                var30 = -var30;
415                var18 = -var18;
416            }
417    
418            boolean var33;
419    
420            if (var3 < 0.0D)
421            {
422                if (var9 < 70)
423                {
424                    var9 = 70;
425                }
426    
427                if (var9 > this.field_85192_a.getActualHeight() - 10)
428                {
429                    var9 = this.field_85192_a.getActualHeight() - 10;
430                }
431    
432                var15 = var9;
433    
434                for (var19 = -1; var19 <= 1; ++var19)
435                {
436                    for (var20 = 1; var20 < 3; ++var20)
437                    {
438                        for (var21 = -1; var21 < 3; ++var21)
439                        {
440                            var22 = var29 + (var20 - 1) * var30 + var19 * var18;
441                            var23 = var15 + var21;
442                            var24 = var16 + (var20 - 1) * var18 - var19 * var30;
443                            var33 = var21 < 0;
444                            this.field_85192_a.setBlockWithNotify(var22, var23, var24, var33 ? Block.obsidian.blockID : 0);
445                        }
446                    }
447                }
448            }
449    
450            for (var19 = 0; var19 < 4; ++var19)
451            {
452                this.field_85192_a.editingBlocks = true;
453    
454                for (var20 = 0; var20 < 4; ++var20)
455                {
456                    for (var21 = -1; var21 < 4; ++var21)
457                    {
458                        var22 = var29 + (var20 - 1) * var30;
459                        var23 = var15 + var21;
460                        var24 = var16 + (var20 - 1) * var18;
461                        var33 = var20 == 0 || var20 == 3 || var21 == -1 || var21 == 3;
462                        this.field_85192_a.setBlockWithNotify(var22, var23, var24, var33 ? Block.obsidian.blockID : Block.portal.blockID);
463                    }
464                }
465    
466                this.field_85192_a.editingBlocks = false;
467    
468                for (var20 = 0; var20 < 4; ++var20)
469                {
470                    for (var21 = -1; var21 < 4; ++var21)
471                    {
472                        var22 = var29 + (var20 - 1) * var30;
473                        var23 = var15 + var21;
474                        var24 = var16 + (var20 - 1) * var18;
475                        this.field_85192_a.notifyBlocksOfNeighborChange(var22, var23, var24, this.field_85192_a.getBlockId(var22, var23, var24));
476                    }
477                }
478            }
479    
480            return true;
481        }
482    
483        public void func_85189_a(long par1)
484        {
485            if (par1 % 100L == 0L)
486            {
487                Iterator var3 = this.field_85190_d.iterator();
488                long var4 = par1 - 600L;
489    
490                while (var3.hasNext())
491                {
492                    Long var6 = (Long)var3.next();
493                    PortalPosition var7 = (PortalPosition)this.field_85191_c.getValueByKey(var6.longValue());
494    
495                    if (var7 == null || var7.field_85087_d < var4)
496                    {
497                        var3.remove();
498                        this.field_85191_c.remove(var6.longValue());
499                    }
500                }
501            }
502        }
503    }