Exemplo n.º 1
0
        private void BeginDigging(Coordinates3D target)
        {
            // TODO: Adjust digging time to compensate for latency
            var block = Game.Client.World.GetBlockId(target);

            Game.TargetBlock  = target;
            Game.StartDigging = DateTime.UtcNow;
            Game.EndDigging   = Game.StartDigging.AddMilliseconds(
                BlockProvider.GetHarvestTime(block,
                                             Game.Client.Inventory.Hotbar[Game.Client.HotBarSelection].Id, out _));
            Game.Client.QueuePacket(new PlayerDiggingPacket(
                                        PlayerDiggingPacket.Action.StartDigging,
                                        Game.TargetBlock.X, (sbyte)Game.TargetBlock.Y, Game.TargetBlock.Z,
                                        Game.HighlightedBlockFace));
            NextAnimation = DateTime.UtcNow.AddSeconds(0.25);
        }
Exemplo n.º 2
0
        public static void HandlePlayerDiggingPacket(IPacket _packet, IRemoteClient _client, IMultiplayerServer server)
        {
            var   packet     = (PlayerDiggingPacket)_packet;
            var   client     = (RemoteClient)_client;
            var   world      = _client.World;
            var   position   = new Coordinates3D(packet.X, packet.Y, packet.Z);
            var   descriptor = world.GetBlockData(position);
            var   provider   = server.BlockRepository.GetBlockProvider(descriptor.ID);
            short damage;
            int   time;

            switch (packet.PlayerAction)
            {
            case PlayerDiggingPacket.Action.DropItem:
                // Throwing item
                if (client.SelectedItem.Empty)
                {
                    break;
                }
                var spawned = client.SelectedItem;
                spawned.Count = 1;
                var inventory = client.SelectedItem;
                inventory.Count--;
                var item = new ItemEntity(client.Entity.Position + new Vector3(0, PlayerEntity.Height, 0), spawned);
                item.Velocity = MathHelper.FowardVector(client.Entity.Yaw) * 0.3;
                client.Inventory[client.SelectedSlot] = inventory;
                server.GetEntityManagerForWorld(client.World).SpawnEntity(item);
                break;

            case PlayerDiggingPacket.Action.StartDigging:
                foreach (var nearbyClient in server.Clients)     // TODO: Send this repeatedly during the course of the digging
                {
                    var c = (RemoteClient)nearbyClient;
                    if (c.KnownEntities.Contains(client.Entity))
                    {
                        c.QueuePacket(new AnimationPacket(client.Entity.EntityID, AnimationPacket.PlayerAnimation.SwingArm));
                    }
                }
                if (provider == null)
                {
                    server.SendMessage(ChatColor.Red + "WARNING: block provider for ID {0} is null (player digging)", descriptor.ID);
                }
                else
                {
                    provider.BlockLeftClicked(descriptor, packet.Face, world, client);
                }

                // "But why on Earth does this behavior change if you use shears on leaves?"
                // "This is poor seperation of concerns"
                // "Let me do a git blame and flame whoever wrote the next line"
                // To answer all of those questions, here:
                // Minecraft sends a player digging packet when the player starts and stops digging a block (two packets)
                // However, it only sends ONE packet if the block would be mined immediately - which usually is only the case
                // for blocks that have a hardness equal to zero.
                // The exception to this rule is shears on leaves. Leaves normally have a hardness of 0.2, but when you mine them
                // using shears the client only sends the start digging packet and expects them to be mined immediately.
                // So if you want to blame anyone, send flames to Notch for the stupid idea of not sending "stop digging" packets
                // for hardness == 0 blocks.

                time = BlockProvider.GetHarvestTime(descriptor.ID, client.SelectedItem.ID, out damage);
                if (time <= 20)
                {
                    provider.BlockMined(descriptor, packet.Face, world, client);
                    break;
                }
                client.ExpectedDigComplete = DateTime.UtcNow.AddMilliseconds(time);
                break;

            case PlayerDiggingPacket.Action.StopDigging:
                foreach (var nearbyClient in server.Clients)
                {
                    var c = (RemoteClient)nearbyClient;
                    if (c.KnownEntities.Contains(client.Entity))
                    {
                        c.QueuePacket(new AnimationPacket(client.Entity.EntityID, AnimationPacket.PlayerAnimation.None));
                    }
                }
                if (provider != null && descriptor.ID != 0)
                {
                    time = BlockProvider.GetHarvestTime(descriptor.ID, client.SelectedItem.ID, out damage);
                    if (time <= 20)
                    {
                        break;     // Already handled earlier
                    }
                    var diff = (DateTime.UtcNow - client.ExpectedDigComplete).TotalMilliseconds;
                    if (diff > -100)     // Allow a small tolerance
                    {
                        provider.BlockMined(descriptor, packet.Face, world, client);
                        // Damage the item
                        if (damage != 0)
                        {
                            var tool = server.ItemRepository.GetItemProvider(client.SelectedItem.ID) as ToolItem;
                            if (tool != null && tool.Uses != -1)
                            {
                                var slot = client.SelectedItem;
                                slot.Metadata += damage;
                                if (slot.Metadata >= tool.Uses)
                                {
                                    slot.Count = 0;     // Destroy item
                                }
                                client.Inventory[client.SelectedSlot] = slot;
                            }
                        }
                    }
                }
                break;
            }
        }