    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}