You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
554 lines
20 KiB
Java
554 lines
20 KiB
Java
package net.minecraft.client.multiplayer;
|
|
|
|
import cpw.mods.fml.relauncher.Side;
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.material.Material;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.audio.PositionedSoundRecord;
|
|
import net.minecraft.client.entity.EntityClientPlayerMP;
|
|
import net.minecraft.client.network.NetHandlerPlayClient;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.passive.EntityHorse;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.item.ItemBlock;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.item.ItemSword;
|
|
import net.minecraft.network.play.client.C02PacketUseEntity;
|
|
import net.minecraft.network.play.client.C07PacketPlayerDigging;
|
|
import net.minecraft.network.play.client.C08PacketPlayerBlockPlacement;
|
|
import net.minecraft.network.play.client.C09PacketHeldItemChange;
|
|
import net.minecraft.network.play.client.C0EPacketClickWindow;
|
|
import net.minecraft.network.play.client.C10PacketCreativeInventoryAction;
|
|
import net.minecraft.network.play.client.C11PacketEnchantItem;
|
|
import net.minecraft.stats.StatFileWriter;
|
|
import net.minecraft.util.ChatComponentText;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraft.util.Vec3;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldSettings;
|
|
|
|
import net.minecraftforge.common.ForgeHooks;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
public class PlayerControllerMP
|
|
{
|
|
/** The Minecraft instance. */
|
|
private final Minecraft mc;
|
|
private final NetHandlerPlayClient netClientHandler;
|
|
/** PosX of the current block being destroyed */
|
|
private int currentBlockX = -1;
|
|
/** PosY of the current block being destroyed */
|
|
private int currentBlockY = -1;
|
|
/** PosZ of the current block being destroyed */
|
|
private int currentblockZ = -1;
|
|
/** The Item currently being used to destroy a block */
|
|
private ItemStack currentItemHittingBlock;
|
|
/** Current block damage (MP) */
|
|
private float curBlockDamageMP;
|
|
/** Tick counter, when it hits 4 it resets back to 0 and plays the step sound */
|
|
private float stepSoundTickCounter;
|
|
/** Delays the first damage on the block after the first click on the block */
|
|
private int blockHitDelay;
|
|
/** Tells if the player is hitting a block */
|
|
private boolean isHittingBlock;
|
|
/** Current game type for the player */
|
|
private WorldSettings.GameType currentGameType;
|
|
/** Index of the current item held by the player in the inventory hotbar */
|
|
private int currentPlayerItem;
|
|
private static final String __OBFID = "CL_00000881";
|
|
|
|
public PlayerControllerMP(Minecraft p_i45062_1_, NetHandlerPlayClient p_i45062_2_)
|
|
{
|
|
this.currentGameType = WorldSettings.GameType.SURVIVAL;
|
|
this.mc = p_i45062_1_;
|
|
this.netClientHandler = p_i45062_2_;
|
|
}
|
|
|
|
/**
|
|
* Block dig operation in creative mode (instantly digs the block).
|
|
*/
|
|
public static void clickBlockCreative(Minecraft minecraftIn, PlayerControllerMP playerController, int x, int y, int z, int side)
|
|
{
|
|
if (!minecraftIn.theWorld.extinguishFire(minecraftIn.thePlayer, x, y, z, side))
|
|
{
|
|
playerController.onPlayerDestroyBlock(x, y, z, side);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets player capabilities depending on current gametype. params: player
|
|
*/
|
|
public void setPlayerCapabilities(EntityPlayer p_78748_1_)
|
|
{
|
|
this.currentGameType.configurePlayerCapabilities(p_78748_1_.capabilities);
|
|
}
|
|
|
|
/**
|
|
* If modified to return true, the player spins around slowly around (0, 68.5, 0). The GUI is disabled, the view is
|
|
* set to first person, and both chat and menu are disabled. Unless the server is modified to ignore illegal
|
|
* stances, attempting to enter a world at all will result in an immediate kick due to an illegal stance. Appears to
|
|
* be left-over debug, or demo code.
|
|
*/
|
|
public boolean enableEverythingIsScrewedUpMode()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sets the game type for the player.
|
|
*/
|
|
public void setGameType(WorldSettings.GameType p_78746_1_)
|
|
{
|
|
this.currentGameType = p_78746_1_;
|
|
this.currentGameType.configurePlayerCapabilities(this.mc.thePlayer.capabilities);
|
|
}
|
|
|
|
/**
|
|
* Flips the player around. Args: player
|
|
*/
|
|
public void flipPlayer(EntityPlayer player)
|
|
{
|
|
player.rotationYaw = -180.0F;
|
|
}
|
|
|
|
public boolean shouldDrawHUD()
|
|
{
|
|
return this.currentGameType.isSurvivalOrAdventure();
|
|
}
|
|
|
|
/**
|
|
* Called when a player completes the destruction of a block
|
|
*/
|
|
public boolean onPlayerDestroyBlock(int x, int y, int z, int side)
|
|
{
|
|
ItemStack stack = mc.thePlayer.getCurrentEquippedItem();
|
|
if (stack != null && stack.getItem() != null && stack.getItem().onBlockStartBreak(stack, x, y, z, mc.thePlayer))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (this.currentGameType.isAdventure() && !this.mc.thePlayer.isCurrentToolAdventureModeExempt(x, y, z))
|
|
{
|
|
return false;
|
|
}
|
|
else if (this.currentGameType.isCreative() && this.mc.thePlayer.getHeldItem() != null && this.mc.thePlayer.getHeldItem().getItem() instanceof ItemSword)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
WorldClient worldclient = this.mc.theWorld;
|
|
Block block = worldclient.getBlock(x, y, z);
|
|
|
|
if (block.getMaterial() == Material.air)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
worldclient.playAuxSFX(2001, x, y, z, Block.getIdFromBlock(block) + (worldclient.getBlockMetadata(x, y, z) << 12));
|
|
int i1 = worldclient.getBlockMetadata(x, y, z);
|
|
boolean flag = block.removedByPlayer(worldclient, mc.thePlayer, x, y, z);
|
|
|
|
if (flag)
|
|
{
|
|
block.onBlockDestroyedByPlayer(worldclient, x, y, z, i1);
|
|
}
|
|
|
|
this.currentBlockY = -1;
|
|
|
|
if (!this.currentGameType.isCreative())
|
|
{
|
|
ItemStack itemstack = this.mc.thePlayer.getCurrentEquippedItem();
|
|
|
|
if (itemstack != null)
|
|
{
|
|
itemstack.func_150999_a(worldclient, block, x, y, z, this.mc.thePlayer);
|
|
|
|
if (itemstack.stackSize == 0)
|
|
{
|
|
this.mc.thePlayer.destroyCurrentEquippedItem();
|
|
}
|
|
}
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called by Minecraft class when the player is hitting a block with an item. Args: x, y, z, side
|
|
*/
|
|
public void clickBlock(int x, int y, int z, int side)
|
|
{
|
|
if (!this.currentGameType.isAdventure() || this.mc.thePlayer.isCurrentToolAdventureModeExempt(x, y, z))
|
|
{
|
|
if (this.currentGameType.isCreative())
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(0, x, y, z, side));
|
|
clickBlockCreative(this.mc, this, x, y, z, side);
|
|
this.blockHitDelay = 5;
|
|
}
|
|
else if (!this.isHittingBlock || !this.sameToolAndBlock(x, y, z))
|
|
{
|
|
if (this.isHittingBlock)
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(1, this.currentBlockX, this.currentBlockY, this.currentblockZ, side));
|
|
}
|
|
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(0, x, y, z, side));
|
|
Block block = this.mc.theWorld.getBlock(x, y, z);
|
|
boolean flag = block.getMaterial() != Material.air;
|
|
|
|
if (flag && this.curBlockDamageMP == 0.0F)
|
|
{
|
|
block.onBlockClicked(this.mc.theWorld, x, y, z, this.mc.thePlayer);
|
|
}
|
|
|
|
if (flag && block.getPlayerRelativeBlockHardness(this.mc.thePlayer, this.mc.thePlayer.worldObj, x, y, z) >= 1.0F)
|
|
{
|
|
this.onPlayerDestroyBlock(x, y, z, side);
|
|
}
|
|
else
|
|
{
|
|
this.isHittingBlock = true;
|
|
this.currentBlockX = x;
|
|
this.currentBlockY = y;
|
|
this.currentblockZ = z;
|
|
this.currentItemHittingBlock = this.mc.thePlayer.getHeldItem();
|
|
this.curBlockDamageMP = 0.0F;
|
|
this.stepSoundTickCounter = 0.0F;
|
|
this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.getEntityId(), this.currentBlockX, this.currentBlockY, this.currentblockZ, (int)(this.curBlockDamageMP * 10.0F) - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resets current block damage and field_78778_j
|
|
*/
|
|
public void resetBlockRemoving()
|
|
{
|
|
if (this.isHittingBlock)
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(1, this.currentBlockX, this.currentBlockY, this.currentblockZ, -1));
|
|
}
|
|
|
|
this.isHittingBlock = false;
|
|
this.curBlockDamageMP = 0.0F;
|
|
this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.getEntityId(), this.currentBlockX, this.currentBlockY, this.currentblockZ, -1);
|
|
}
|
|
|
|
/**
|
|
* Called when a player damages a block and updates damage counters
|
|
*/
|
|
public void onPlayerDamageBlock(int x, int y, int z, int side)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
|
|
if (this.blockHitDelay > 0)
|
|
{
|
|
--this.blockHitDelay;
|
|
}
|
|
else if (this.currentGameType.isCreative())
|
|
{
|
|
this.blockHitDelay = 5;
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(0, x, y, z, side));
|
|
clickBlockCreative(this.mc, this, x, y, z, side);
|
|
}
|
|
else
|
|
{
|
|
if (this.sameToolAndBlock(x, y, z))
|
|
{
|
|
Block block = this.mc.theWorld.getBlock(x, y, z);
|
|
|
|
if (block.getMaterial() == Material.air)
|
|
{
|
|
this.isHittingBlock = false;
|
|
return;
|
|
}
|
|
|
|
this.curBlockDamageMP += block.getPlayerRelativeBlockHardness(this.mc.thePlayer, this.mc.thePlayer.worldObj, x, y, z);
|
|
|
|
if (this.stepSoundTickCounter % 4.0F == 0.0F)
|
|
{
|
|
this.mc.getSoundHandler().playSound(new PositionedSoundRecord(new ResourceLocation(block.stepSound.getStepResourcePath()), (block.stepSound.getVolume() + 1.0F) / 8.0F, block.stepSound.getPitch() * 0.5F, (float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F));
|
|
}
|
|
|
|
++this.stepSoundTickCounter;
|
|
|
|
if (this.curBlockDamageMP >= 1.0F)
|
|
{
|
|
this.isHittingBlock = false;
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(2, x, y, z, side));
|
|
this.onPlayerDestroyBlock(x, y, z, side);
|
|
this.curBlockDamageMP = 0.0F;
|
|
this.stepSoundTickCounter = 0.0F;
|
|
this.blockHitDelay = 5;
|
|
}
|
|
|
|
this.mc.theWorld.destroyBlockInWorldPartially(this.mc.thePlayer.getEntityId(), this.currentBlockX, this.currentBlockY, this.currentblockZ, (int)(this.curBlockDamageMP * 10.0F) - 1);
|
|
}
|
|
else
|
|
{
|
|
this.clickBlock(x, y, z, side);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* player reach distance = 4F
|
|
*/
|
|
public float getBlockReachDistance()
|
|
{
|
|
return this.currentGameType.isCreative() ? 5.0F : 4.5F;
|
|
}
|
|
|
|
public void updateController()
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
|
|
if (this.netClientHandler.getNetworkManager().isChannelOpen())
|
|
{
|
|
this.netClientHandler.getNetworkManager().processReceivedPackets();
|
|
}
|
|
else if (this.netClientHandler.getNetworkManager().getExitMessage() != null)
|
|
{
|
|
this.netClientHandler.getNetworkManager().getNetHandler().onDisconnect(this.netClientHandler.getNetworkManager().getExitMessage());
|
|
}
|
|
else
|
|
{
|
|
this.netClientHandler.getNetworkManager().getNetHandler().onDisconnect(new ChatComponentText("Disconnected from server"));
|
|
}
|
|
}
|
|
|
|
private boolean sameToolAndBlock(int x, int y, int z)
|
|
{
|
|
ItemStack itemstack = this.mc.thePlayer.getHeldItem();
|
|
boolean flag = this.currentItemHittingBlock == null && itemstack == null;
|
|
|
|
if (this.currentItemHittingBlock != null && itemstack != null)
|
|
{
|
|
flag = itemstack.getItem() == this.currentItemHittingBlock.getItem() && ItemStack.areItemStackTagsEqual(itemstack, this.currentItemHittingBlock) && (itemstack.isItemStackDamageable() || itemstack.getItemDamage() == this.currentItemHittingBlock.getItemDamage());
|
|
}
|
|
|
|
return x == this.currentBlockX && y == this.currentBlockY && z == this.currentblockZ && flag;
|
|
}
|
|
|
|
/**
|
|
* Syncs the current player item with the server
|
|
*/
|
|
private void syncCurrentPlayItem()
|
|
{
|
|
int i = this.mc.thePlayer.inventory.currentItem;
|
|
|
|
if (i != this.currentPlayerItem)
|
|
{
|
|
this.currentPlayerItem = i;
|
|
this.netClientHandler.addToSendQueue(new C09PacketHeldItemChange(this.currentPlayerItem));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles a players right click. Args: player, world, x, y, z, side, hitVec
|
|
*/
|
|
public boolean onPlayerRightClick(EntityPlayer player, World worldIn, ItemStack itemStackIn, int x, int y, int z, int side, Vec3 hitVector)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
float f = (float)hitVector.xCoord - (float)x;
|
|
float f1 = (float)hitVector.yCoord - (float)y;
|
|
float f2 = (float)hitVector.zCoord - (float)z;
|
|
boolean flag = false;
|
|
|
|
if (itemStackIn != null &&
|
|
itemStackIn.getItem() != null &&
|
|
itemStackIn.getItem().onItemUseFirst(itemStackIn, player, worldIn, x, y, z, side, f, f1, f2))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!player.isSneaking() || player.getHeldItem() == null || player.getHeldItem().getItem().doesSneakBypassUse(worldIn, x, y, z, player))
|
|
{
|
|
flag = worldIn.getBlock(x, y, z).onBlockActivated(worldIn, x, y, z, player, side, f, f1, f2);
|
|
}
|
|
|
|
if (!flag && itemStackIn != null && itemStackIn.getItem() instanceof ItemBlock)
|
|
{
|
|
ItemBlock itemblock = (ItemBlock)itemStackIn.getItem();
|
|
|
|
if (!itemblock.func_150936_a(worldIn, x, y, z, side, player, itemStackIn))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this.netClientHandler.addToSendQueue(new C08PacketPlayerBlockPlacement(x, y, z, side, player.inventory.getCurrentItem(), f, f1, f2));
|
|
|
|
if (flag)
|
|
{
|
|
return true;
|
|
}
|
|
else if (itemStackIn == null)
|
|
{
|
|
return false;
|
|
}
|
|
else if (this.currentGameType.isCreative())
|
|
{
|
|
int j1 = itemStackIn.getItemDamage();
|
|
int i1 = itemStackIn.stackSize;
|
|
boolean flag1 = itemStackIn.tryPlaceItemIntoWorld(player, worldIn, x, y, z, side, f, f1, f2);
|
|
itemStackIn.setItemDamage(j1);
|
|
itemStackIn.stackSize = i1;
|
|
return flag1;
|
|
}
|
|
else
|
|
{
|
|
if (!itemStackIn.tryPlaceItemIntoWorld(player, worldIn, x, y, z, side, f, f1, f2))
|
|
{
|
|
return false;
|
|
}
|
|
if (itemStackIn.stackSize <= 0)
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, itemStackIn));
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Notifies the server of things like consuming food, etc...
|
|
*/
|
|
public boolean sendUseItem(EntityPlayer player, World worldIn, ItemStack itemStackIn)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
this.netClientHandler.addToSendQueue(new C08PacketPlayerBlockPlacement(-1, -1, -1, 255, player.inventory.getCurrentItem(), 0.0F, 0.0F, 0.0F));
|
|
int i = itemStackIn.stackSize;
|
|
ItemStack itemstack1 = itemStackIn.useItemRightClick(worldIn, player);
|
|
|
|
if (itemstack1 == itemStackIn && (itemstack1 == null || itemstack1.stackSize == i))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
player.inventory.mainInventory[player.inventory.currentItem] = itemstack1;
|
|
|
|
if (itemstack1.stackSize <= 0)
|
|
{
|
|
player.inventory.mainInventory[player.inventory.currentItem] = null;
|
|
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, itemstack1));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public EntityClientPlayerMP func_147493_a(World worldIn, StatFileWriter stats)
|
|
{
|
|
return new EntityClientPlayerMP(this.mc, worldIn, this.mc.getSession(), this.netClientHandler, stats);
|
|
}
|
|
|
|
/**
|
|
* Attacks an entity
|
|
*/
|
|
public void attackEntity(EntityPlayer player, Entity targetEntity)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
this.netClientHandler.addToSendQueue(new C02PacketUseEntity(targetEntity, C02PacketUseEntity.Action.ATTACK));
|
|
player.attackTargetEntityWithCurrentItem(targetEntity);
|
|
}
|
|
|
|
/**
|
|
* Send packet to server - player is interacting with another entity (left click)
|
|
*/
|
|
public boolean interactWithEntitySendPacket(EntityPlayer player, Entity targetEntity)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
this.netClientHandler.addToSendQueue(new C02PacketUseEntity(targetEntity, C02PacketUseEntity.Action.INTERACT));
|
|
return player.interactWith(targetEntity);
|
|
}
|
|
|
|
public ItemStack windowClick(int windowId, int slotId, int p_78753_3_, int p_78753_4_, EntityPlayer player)
|
|
{
|
|
short short1 = player.openContainer.getNextTransactionID(player.inventory);
|
|
ItemStack itemstack = player.openContainer.slotClick(slotId, p_78753_3_, p_78753_4_, player);
|
|
this.netClientHandler.addToSendQueue(new C0EPacketClickWindow(windowId, slotId, p_78753_3_, p_78753_4_, itemstack, short1));
|
|
return itemstack;
|
|
}
|
|
|
|
/**
|
|
* GuiEnchantment uses this during multiplayer to tell PlayerControllerMP to send a packet indicating the
|
|
* enchantment action the player has taken.
|
|
*/
|
|
public void sendEnchantPacket(int p_78756_1_, int p_78756_2_)
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C11PacketEnchantItem(p_78756_1_, p_78756_2_));
|
|
}
|
|
|
|
/**
|
|
* Used in PlayerControllerMP to update the server with an ItemStack in a slot.
|
|
*/
|
|
public void sendSlotPacket(ItemStack itemStackIn, int slotId)
|
|
{
|
|
if (this.currentGameType.isCreative())
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C10PacketCreativeInventoryAction(slotId, itemStackIn));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a Packet107 to the server to drop the item on the ground
|
|
*/
|
|
public void sendPacketDropItem(ItemStack itemStackIn)
|
|
{
|
|
if (this.currentGameType.isCreative() && itemStackIn != null)
|
|
{
|
|
this.netClientHandler.addToSendQueue(new C10PacketCreativeInventoryAction(-1, itemStackIn));
|
|
}
|
|
}
|
|
|
|
public void onStoppedUsingItem(EntityPlayer player)
|
|
{
|
|
this.syncCurrentPlayItem();
|
|
this.netClientHandler.addToSendQueue(new C07PacketPlayerDigging(5, 0, 0, 0, 255));
|
|
player.stopUsingItem();
|
|
}
|
|
|
|
public boolean gameIsSurvivalOrAdventure()
|
|
{
|
|
return this.currentGameType.isSurvivalOrAdventure();
|
|
}
|
|
|
|
/**
|
|
* Checks if the player is not creative, used for checking if it should break a block instantly
|
|
*/
|
|
public boolean isNotCreative()
|
|
{
|
|
return !this.currentGameType.isCreative();
|
|
}
|
|
|
|
/**
|
|
* returns true if player is in creative mode
|
|
*/
|
|
public boolean isInCreativeMode()
|
|
{
|
|
return this.currentGameType.isCreative();
|
|
}
|
|
|
|
/**
|
|
* true for hitting entities far away.
|
|
*/
|
|
public boolean extendedReach()
|
|
{
|
|
return this.currentGameType.isCreative();
|
|
}
|
|
|
|
public boolean func_110738_j()
|
|
{
|
|
return this.mc.thePlayer.isRiding() && this.mc.thePlayer.ridingEntity instanceof EntityHorse;
|
|
}
|
|
} |