func (player *Player) PacketPlayerBlockHit(status DigStatus, target *BlockXyz, face Face) { player.lock.Lock() defer player.lock.Unlock() // This packet handles 'throwing' an item as well, with status = 4, and // the zero values for target and face, so check for that. if status == DigDropItem && target.IsZero() && face == 0 { blockLoc := player.position.ToBlockXyz() shardClient, _, ok := player.chunkSubs.ShardClientForBlockXyz(blockLoc) if !ok { return } var itemToThrow gamerules.Slot player.inventory.TakeOneHeldItem(&itemToThrow) if !itemToThrow.IsEmpty() { velocity := physics.VelocityFromLook(player.look, 0.50) position := player.position position.Y += player.height shardClient.ReqDropItem(itemToThrow, position, velocity, TicksPerSecond/2) } return } // Validate that the player is actually somewhere near the block. targetAbsPos := target.MidPointToAbsXyz() if !targetAbsPos.IsWithinDistanceOf(&player.position, MaxInteractDistance) { log.Printf("Player/PacketPlayerBlockHit: ignoring player dig at %v (too far away)", target) return } // TODO measure the dig time on the target block and relay to the shard to // stop speed hacking (based on block type and tool used - non-trivial). shardClient, _, ok := player.chunkSubs.ShardClientForBlockXyz(target) if ok { held, _ := player.inventory.HeldItem() shardClient.ReqHitBlock(held, *target, status, face) } }