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