    001    package net.minecraft.src;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import net.minecraft.client.Minecraft;
    006    import net.minecraftforge.common.ForgeHooks;
    007    import net.minecraftforge.common.MinecraftForge;
    008    import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
    009
    010    @SideOnly(Side.CLIENT)
    011    public class PlayerControllerMP
    012    {
    013        /** The Minecraft instance. */
    014        private final Minecraft mc;
    015        private final NetClientHandler netClientHandler;
    016
    017        /** PosX of the current block being destroyed */
    018        private int currentBlockX = -1;
    019
    020        /** PosY of the current block being destroyed */
    021        private int currentBlockY = -1;
    022
    023        /** PosZ of the current block being destroyed */
    024        private int currentblockZ = -1;
    025        private ItemStack field_85183_f = null;
    026
    027        /** Current block damage (MP) */
    028        private float curBlockDamageMP = 0.0F;
    029
    030        /** Previous block damage (MP) */
    031        private float prevBlockDamageMP = 0.0F;
    032
    033        /**
    034         * Tick counter, when it hits 4 it resets back to 0 and plays the step sound
    035         */
    036        private float stepSoundTickCounter = 0.0F;
    037
    038        /**
    039         * Delays the first damage on the block after the first click on the block
    040         */
    041        private int blockHitDelay = 0;
    042
    043        /** Tells if the player is hitting a block */
    044        private boolean isHittingBlock = false;
    045
    046        /** Current game type for the player */
    047        private EnumGameType currentGameType;
    048
    049        /** Index of the current item held by the player in the inventory hotbar */
    050        private int currentPlayerItem;
    051
    052        public PlayerControllerMP(Minecraft par1Minecraft, NetClientHandler par2NetClientHandler)
    053        {
    054            this.currentGameType = EnumGameType.SURVIVAL;
    055            this.currentPlayerItem = 0;
    056            this.mc = par1Minecraft;
    057            this.netClientHandler = par2NetClientHandler;
    058        }
    059
    060        /**
    061         * Block dig operation in creative mode (instantly digs the block).
    062         */
    063        public static void clickBlockCreative(Minecraft par0Minecraft, PlayerControllerMP par1PlayerControllerMP, int par2, int par3, int par4, int par5)
    064        {
    065            if (!par0Minecraft.theWorld.extinguishFire(par0Minecraft.thePlayer, par2, par3, par4, par5))
    066            {
    067                par1PlayerControllerMP.onPlayerDestroyBlock(par2, par3, par4, par5);
    068            }
    069        }
    070
    071        /**
    072         * Sets player capabilities depending on current gametype. params: player
    073         */
    074        public void setPlayerCapabilities(EntityPlayer par1EntityPlayer)
    075        {
    076            this.currentGameType.configurePlayerCapabilities(par1EntityPlayer.capabilities);
    077        }
    078
    079        public boolean func_78747_a()
    080        {
    081            return false;
    082        }
    083
    084        /**
    085         * Sets the game type for the player.
    086         */
    087        public void setGameType(EnumGameType par1EnumGameType)
    088        {
    089            this.currentGameType = par1EnumGameType;
    090            this.currentGameType.configurePlayerCapabilities(this.mc.thePlayer.capabilities);
    091        }
    092
    093        /**
    094         * Flips the player around. Args: player
    095         */
    096        public void flipPlayer(EntityPlayer par1EntityPlayer)
    097        {
    098            par1EntityPlayer.rotationYaw = -180.0F;
    099        }
    100
    101        public boolean shouldDrawHUD()
    102        {
    103            return this.currentGameType.isSurvivalOrAdventure();
    104        }
    105
    106        /**
    107         * Called when a player completes the destruction of a block
    108         */
    109        public boolean onPlayerDestroyBlock(int par1, int par2, int par3, int par4)
    110        {
    111            ItemStack stack = mc.thePlayer.getCurrentEquippedItem();
    112            if (stack != null && stack.getItem() != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, mc.thePlayer))
    113            {
    114                return false;
    115            }
    116
    117            if (this.currentGameType.isAdventure() && !this.mc.thePlayer.canCurrentToolHarvestBlock(par1, par2, par3))
    118            {
    119                return false;
    120            }
    121            else
    122            {
    123                WorldClient var5 = this.mc.theWorld;
    124                Block var6 = Block.blocksList[var5.getBlockId(par1, par2, par3)];
    125
    126                if (var6 == null)
    127                {
    128                    return false;
    129                }
    130                else
    131                {
    132                    var5.playAuxSFX(2001, par1, par2, par3, var6.blockID + (var5.getBlockMetadata(par1, par2, par3) << 12));
    133                    int var7 = var5.getBlockMetadata(par1, par2, par3);
    134                    boolean var8 = var6.removeBlockByPlayer(var5, mc.thePlayer, par1, par2, par3);
    135
    136                    if (var8)
    137                    {
    138                        var6.onBlockDestroyedByPlayer(var5, par1, par2, par3, var7);
    139                    }
    140
    141                    this.currentBlockY = -1;
    142
    143                    if (!this.currentGameType.isCreative())
    144                    {
    145                        ItemStack var9 = this.mc.thePlayer.getCurrentEquippedItem();
    146
    147                        if (var9 != null)
    148                        {
    149                            var9.onBlockDestroyed(var5, var6.blockID, par1, par2, par3, this.mc.thePlayer);
    150
    151                            if (var9.stackSize == 0)
    152                            {
    153                                this.mc.thePlayer.destroyCurrentEquippedItem();
    154                            }
    155                        }
    156                    }
    157
    158                    return var8;
    159                }
    160            }
    161        }
    162
    163        /**
    164         * Called by Minecraft class when the player is hitting a block with an item. Args: x, y, z, side
    165         */
    166        public void clickBlock(int par1, int par2, int par3, int par4)
    167        {
    168            if (!this.currentGameType.isAdventure() || this.mc.thePlayer.canCurrentToolHarvestBlock(par1, par2, par3))
    169            {
    170                if (this.currentGameType.isCreative())
    171                {
    172                    this.netClientHandler.addToSendQueue(new Packet14BlockDig(0, par1, par2, par3, par4));
    173                    clickBlockCreative(this.mc, this, par1, par2, par3, par4);
    174                    this.blockHitDelay = 5;
    175                }
    176                else if (!this.isHittingBlock || !this.func_85182_a(par1, par2, par3))
    177                {
    178                    if (this.isHittingBlock)
    179                    {
    180                        this.netClientHandler.addToSendQueue(new Packet14BlockDig(1, this.currentBlockX, this.currentBlockY, this.currentblockZ, par4));
    181                    }
    182
    183                    this.netClientHandler.addToSendQueue(new Packet14BlockDig(0, par1, par2, par3, par4));
    184                    int var5 = this.mc.theWorld.getBlockId(par1, par2, par3);
    185
    186                    if (var5 > 0 && this.curBlockDamageMP == 0.0F)
    187                    {
    188                        Block.blocksList[var5].onBlockClicked(this.mc.theWorld, par1, par2, par3, this.mc.thePlayer);
    189                    }
    190
    191                    if (var5 > 0 && Block.blocksList[var5].getPlayerRelativeBlockHardness(this.mc.thePlayer, this.mc.thePlayer.worldObj, par1, par2, par3) >= 1.0F)
    192                    {
    193                        this.onPlayerDestroyBlock(par1, par2, par3, par4);
    194                    }
    195                    else
    196                    {
    197                        this.isHittingBlock = true;
    198                        this.currentBlockX = par1;
    199                        this.currentBlockY = par2;
    200                        this.currentblockZ = par3;
    201                        this.field_85183_f = this.mc.thePlayer.getHeldItem();
    202                        this.curBlockDamageMP = 0.0F;
    203                        this.prevBlockDamageMP = 0.0F;
    204                        this.stepSoundTickCounter = 0.0F;
    205                        this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.entityId, this.currentBlockX, this.currentBlockY, this.currentblockZ, (int)(this.curBlockDamageMP * 10.0F) - 1);
    206                    }
    207                }
    208            }
    209        }
    210
    211        /**
    212         * Resets current block damage and isHittingBlock
    213         */
    214        public void resetBlockRemoving()
    215        {
    216            if (this.isHittingBlock)
    217            {
    218                this.netClientHandler.addToSendQueue(new Packet14BlockDig(1, this.currentBlockX, this.currentBlockY, this.currentblockZ, -1));
    219            }
    220
    221            this.isHittingBlock = false;
    222            this.curBlockDamageMP = 0.0F;
    223            this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.entityId, this.currentBlockX, this.currentBlockY, this.currentblockZ, -1);
    224        }
    225
    226        /**
    227         * Called when a player damages a block and updates damage counters
    228         */
    229        public void onPlayerDamageBlock(int par1, int par2, int par3, int par4)
    230        {
    231            this.syncCurrentPlayItem();
    232
    233            if (this.blockHitDelay > 0)
    234            {
    235                --this.blockHitDelay;
    236            }
    237            else if (this.currentGameType.isCreative())
    238            {
    239                this.blockHitDelay = 5;
    240                this.netClientHandler.addToSendQueue(new Packet14BlockDig(0, par1, par2, par3, par4));
    241                clickBlockCreative(this.mc, this, par1, par2, par3, par4);
    242            }
    243            else
    244            {
    245                if (this.func_85182_a(par1, par2, par3))
    246                {
    247                    int var5 = this.mc.theWorld.getBlockId(par1, par2, par3);
    248
    249                    if (var5 == 0)
    250                    {
    251                        this.isHittingBlock = false;
    252                        return;
    253                    }
    254
    255                    Block var6 = Block.blocksList[var5];
    256                    this.curBlockDamageMP += var6.getPlayerRelativeBlockHardness(this.mc.thePlayer, this.mc.thePlayer.worldObj, par1, par2, par3);
    257
    258                    if (this.stepSoundTickCounter % 4.0F == 0.0F && var6 != null)
    259                    {
    260                        this.mc.sndManager.playSound(var6.stepSound.getStepSound(), (float)par1 + 0.5F, (float)par2 + 0.5F, (float)par3 + 0.5F, (var6.stepSound.getVolume() + 1.0F) / 8.0F, var6.stepSound.getPitch() * 0.5F);
    261                    }
    262
    263                    ++this.stepSoundTickCounter;
    264
    265                    if (this.curBlockDamageMP >= 1.0F)
    266                    {
    267                        this.isHittingBlock = false;
    268                        this.netClientHandler.addToSendQueue(new Packet14BlockDig(2, par1, par2, par3, par4));
    269                        this.onPlayerDestroyBlock(par1, par2, par3, par4);
    270                        this.curBlockDamageMP = 0.0F;
    271                        this.prevBlockDamageMP = 0.0F;
    272                        this.stepSoundTickCounter = 0.0F;
    273                        this.blockHitDelay = 5;
    274                    }
    275
    276                    this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.entityId, this.currentBlockX, this.currentBlockY, this.currentblockZ, (int)(this.curBlockDamageMP * 10.0F) - 1);
    277                }
    278                else
    279                {
    280                    this.clickBlock(par1, par2, par3, par4);
    281                }
    282            }
    283        }
    284
    285        /**
    286         * player reach distance = 4F
    287         */
    288        public float getBlockReachDistance()
    289        {
    290            return this.currentGameType.isCreative() ? 5.0F : 4.5F;
    291        }
    292
    293        public void updateController()
    294        {
    295            this.syncCurrentPlayItem();
    296            this.prevBlockDamageMP = this.curBlockDamageMP;
    297            this.mc.sndManager.playRandomMusicIfReady();
    298        }
    299
    300        private boolean func_85182_a(int par1, int par2, int par3)
    301        {
    302            return par1 == this.currentBlockX && par2 == this.currentBlockY && par3 == this.currentblockZ && this.field_85183_f == this.mc.thePlayer.getHeldItem();
    303        }
    304
    305        /**
    306         * Syncs the current player item with the server
    307         */
    308        private void syncCurrentPlayItem()
    309        {
    310            int var1 = this.mc.thePlayer.inventory.currentItem;
    311
    312            if (var1 != this.currentPlayerItem)
    313            {
    314                this.currentPlayerItem = var1;
    315                this.netClientHandler.addToSendQueue(new Packet16BlockItemSwitch(this.currentPlayerItem));
    316            }
    317        }
    318
    319        /**
    320         * Handles a players right click. Args: player, world, x, y, z, side, hitVec
    321         */
    322        public boolean onPlayerRightClick(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, Vec3 par8Vec3)
    323        {
    324            this.syncCurrentPlayItem();
    325            float var9 = (float)par8Vec3.xCoord - (float)par4;
    326            float var10 = (float)par8Vec3.yCoord - (float)par5;
    327            float var11 = (float)par8Vec3.zCoord - (float)par6;
    328            boolean var12 = false;
    329            int var13 = par2World.getBlockId(par4, par5, par6);
    330            if (par3ItemStack != null &&
    331                par3ItemStack.getItem() != null &&
    332                par3ItemStack.getItem().onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, var9, var10, var11))
    333            {
    334                    return true;
    335            }
    336
    337            if (var13 > 0 && Block.blocksList[var13].onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, var9, var10, var11))
    338            {
    339                var12 = true;
    340            }
    341
    342            if (!var12 && par3ItemStack != null && par3ItemStack.getItem() instanceof ItemBlock)
    343            {
    344                ItemBlock var14 = (ItemBlock)par3ItemStack.getItem();
    345
    346                if (!var14.canPlaceItemBlockOnSide(par2World, par4, par5, par6, par7, par1EntityPlayer, par3ItemStack))
    347                {
    348                    return false;
    349                }
    350            }
    351
    352            this.netClientHandler.addToSendQueue(new Packet15Place(par4, par5, par6, par7, par1EntityPlayer.inventory.getCurrentItem(), var9, var10, var11));
    353
    354            if (var12)
    355            {
    356                return true;
    357            }
    358            else if (par3ItemStack == null)
    359            {
    360                return false;
    361            }
    362            else if (this.currentGameType.isCreative())
    363            {
    364                int var17 = par3ItemStack.getItemDamage();
    365                int var15 = par3ItemStack.stackSize;
    366                boolean var16 = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, var9, var10, var11);
    367                par3ItemStack.setItemDamage(var17);
    368                par3ItemStack.stackSize = var15;
    369                return var16;
    370            }
    371            else
    372            {
    373                if (!par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, var9, var10, var11))
    374                {
    375                    return false;
    376                }
    377                if (par3ItemStack.stackSize <= 0)
    378                {
    379                    MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(par1EntityPlayer, par3ItemStack));
    380                }
    381                return true;
    382            }
    383        }
    384
    385        /**
    386         * Notifies the server of things like consuming food, etc...
    387         */
    388        public boolean sendUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack)
    389        {
    390            this.syncCurrentPlayItem();
    391            this.netClientHandler.addToSendQueue(new Packet15Place(-1, -1, -1, 255, par1EntityPlayer.inventory.getCurrentItem(), 0.0F, 0.0F, 0.0F));
    392            int var4 = par3ItemStack.stackSize;
    393            ItemStack var5 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer);
    394
    395            if (var5 == par3ItemStack && (var5 == null || var5.stackSize == var4))
    396            {
    397                return false;
    398            }
    399            else
    400            {
    401                par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = var5;
    402
    403                if (var5.stackSize <= 0)
    404                {
    405                    par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null;
    406                    MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(par1EntityPlayer, var5));
    407                }
    408
    409                return true;
    410            }
    411        }
    412
    413        public EntityClientPlayerMP func_78754_a(World par1World)
    414        {
    415            return new EntityClientPlayerMP(this.mc, par1World, this.mc.session, this.netClientHandler);
    416        }
    417
    418        /**
    419         * Attacks an entity
    420         */
    421        public void attackEntity(EntityPlayer par1EntityPlayer, Entity par2Entity)
    422        {
    423            this.syncCurrentPlayItem();
    424            this.netClientHandler.addToSendQueue(new Packet7UseEntity(par1EntityPlayer.entityId, par2Entity.entityId, 1));
    425            par1EntityPlayer.attackTargetEntityWithCurrentItem(par2Entity);
    426        }
    427
    428        public boolean func_78768_b(EntityPlayer par1EntityPlayer, Entity par2Entity)
    429        {
    430            this.syncCurrentPlayItem();
    431            this.netClientHandler.addToSendQueue(new Packet7UseEntity(par1EntityPlayer.entityId, par2Entity.entityId, 0));
    432            return par1EntityPlayer.interactWith(par2Entity);
    433        }
    434
    435        public ItemStack windowClick(int par1, int par2, int par3, int par4, EntityPlayer par5EntityPlayer)
    436        {
    437            short var6 = par5EntityPlayer.craftingInventory.getNextTransactionID(par5EntityPlayer.inventory);
    438            ItemStack var7 = par5EntityPlayer.craftingInventory.slotClick(par2, par3, par4, par5EntityPlayer);
    439            this.netClientHandler.addToSendQueue(new Packet102WindowClick(par1, par2, par3, par4, var7, var6));
    440            return var7;
    441        }
    442
    443        /**
    444         * GuiEnchantment uses this during multiplayer to tell PlayerControllerMP to send a packet indicating the
    445         * enchantment action the player has taken.
    446         */
    447        public void sendEnchantPacket(int par1, int par2)
    448        {
    449            this.netClientHandler.addToSendQueue(new Packet108EnchantItem(par1, par2));
    450        }
    451
    452        /**
    453         * Used in PlayerControllerMP to update the server with an ItemStack in a slot.
    454         */
    455        public void sendSlotPacket(ItemStack par1ItemStack, int par2)
    456        {
    457            if (this.currentGameType.isCreative())
    458            {
    459                this.netClientHandler.addToSendQueue(new Packet107CreativeSetSlot(par2, par1ItemStack));
    460            }
    461        }
    462
    463        public void func_78752_a(ItemStack par1ItemStack)
    464        {
    465            if (this.currentGameType.isCreative() && par1ItemStack != null)
    466            {
    467                this.netClientHandler.addToSendQueue(new Packet107CreativeSetSlot(-1, par1ItemStack));
    468            }
    469        }
    470
    471        public void onStoppedUsingItem(EntityPlayer par1EntityPlayer)
    472        {
    473            this.syncCurrentPlayItem();
    474            this.netClientHandler.addToSendQueue(new Packet14BlockDig(5, 0, 0, 0, 255));
    475            par1EntityPlayer.stopUsingItem();
    476        }
    477
    478        public boolean func_78763_f()
    479        {
    480            return true;
    481        }
    482
    483        /**
    484         * Checks if the player is not creative, used for checking if it should break a block instantly
    485         */
    486        public boolean isNotCreative()
    487        {
    488            return !this.currentGameType.isCreative();
    489        }
    490
    491        /**
    492         * returns true if player is in creative mode
    493         */
    494        public boolean isInCreativeMode()
    495        {
    496            return this.currentGameType.isCreative();
    497        }
    498
    499        /**
    500         * true for hitting entities far away.
    501         */
    502        public boolean extendedReach()
    503        {
    504            return this.currentGameType.isCreative();
    505        }
    506    }