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