Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
Log

Occult practices for finding ore

Recommended Posts

There is an interesting device in the OpenComputers mod that allows you to determine the block hardness at a distance.
But the trouble is, the data it gives out is rather noisy and the greater the distance, the more noise.

To determine the true hardness of a block, we can scan it several times and average the result. The noise that interferes with scanning is of a probabilistic nature. And after several scans, you can statistically find what the most likely hardness of the block is.
In one tick, we can scan 64 blocks. To analyze the entire available area (65 x 65 x 64) with hundred of iterations, we need 422500 ticks, which is equal to 21125 seconds or 352 minutes, that is, almost 6 hours.
But how many times should we scan? One hundred? A thousand?

Secret knowledge is open to us and there is an exact answer.
One. With just one scan, we can find ore among any other blocks. If you want absolute certainty, you will have to do a couple of magic passes and re-scan.

Let's start with theory.

First, open the mod's code and find the geolyzer.scan function, it is located [here] and is called onGeolyzerScan()
Looking at the code, we can understand that the function accepts parameters, by these parameters it scans blocks in the world. Does various checks like world.blockExists(x, y, z) && !world.isAirBlock(x, y, z) to make sure is a block here.
Then he receives information about the block by coordinates, makes a few more checks (checks again that this is a block block != null, checks additional parameters: includeReplaceable, isFluid(block), block.isReplaceable(world, blockPos.x, blockPos.y, blockPos.z))
Then the distance to the block is measured. And at the end, hardness is taken, mixed with noise and distance. The result is added to the block table and sent to the player.

It seems to be nothing unusual. Noise, distance, hardness. We already know the dependence of the strength of the noise on the distance.

And that's where the magic begins.
Let's take a closer look at the code for calculating the final block hardness.

e.data(index) = e.data(index) * distance * Settings.get.geolyzerNoise + block.getBlockHardness(world, x, y, z)

Briefly, we can write this in the form of the formula: R = G * D * N + H
G - the generated noise.
D - distance to the block.
N - noise multiplier from the config (standard - 2).
H - the true hardness.
R - result of the geolyzer.

If we try to subtract the expected hardness from the result as an experiment, we will not learn anything new. If we reverse all operations with known values, then we get only noise.

Can we also parse the noise formula? Let's try.
A few lines above [link]. We can observe the receipt of an array of random bytes.

val noise = new Array[Byte](e.data.length)
world.rand.nextBytes(noise)

This is followed by normalization of values.

noise.map(_ / 128f / 33f).copyToArray(e.data)

Hmm. Well, well, well. If we combine all this with the previous formula, we get something like this:
R = G(RANDOM_BYTE / 128 / 33) * D * N + H

And what does it give us?
And the fact that the original pseudo-random number has a hard discreteness. PRNG gives random numbers of type byte, and these are only 256 values (-128, +127).
We know all the values except H and RANDOM_BYTE, what does this give us?
We can assume the value of H and reverse the entire formula.
(R - H) / D / N * 128 * 33
For a standard config, we can shorten to:
2112 * (R - H) / D

And now I will open the secret knowledge for those who have not yet solved the riddle on their own.

We took the desired block hardness (eg 3 for ore).
Substituted this value for H.
Got a random value.
We can easily determine if the hardness is correct or not.

Due to the discreteness of the random values of PRNG, the probability distribution for blocks with different densities is not the same.

cbdzk30.png

 

Let's put into practice

Here is the code of a simple script that searches for blocks with the desired hardness in a given radius. The result is displayed on the holoprojector.

local sqrt = math.sqrt
local component = require('component')
local geolyzer = component.geolyzer
local hologram = component.hologram

local function distance(x, y, z)
  return sqrt(x^2 + y^2 + z^2)
end

local function magic(R, H, D)
  return 2112 * (R - H) / D % 1
end

local function visualize(hardness, elevation, size)
  hologram.clear()
  hologram.setScale(9)
  local blocks, result
  for x = -size, size do
    for z = -size, size do
      blocks = geolyzer.scan(x, z, elevation, 1, 1, 32)
      for i_y = 1, 32 do
        result = magic(blocks[i_y], hardness, distance(x, i_y+elevation-1, z))
        if blocks[i_y] ~= 0 and (result > 0.9998 or result < 0.00005) then
          hologram.set(x+24, i_y, z+24, true)
        end
      end
    end
  end
end

local hrd, ele, siz = table.unpack({...})
hrd = hrd or 3
ele = ele or -32
siz = siz or 16
visualize(hrd, ele, siz)

And here's the result:

grNrLdJ.pngfZVZjrO.png

When scanning, artifacts are noticeable. When different densities are close at integer distances, collisions occur.
At any distance, we can calculate the absolute minimum and maximum noise levels. With distance, the intersection of values increases for close densities, but if the block hardness is not in the intersection area, then you can determine exactly which area it belongs to.

P4v8cL8.png

The intersection of the densities of ore (3) and stone (1.5), the dots represent three scans of the ore block.

The results of the reverse calculation for different densities demonstrate this well.

onqp1Vm.png

To compensate for artifacts, we need to enter an additional condition: the resulting RANDOM_BYTE must be in the range -128:127.
Here is the final script and the result.

local sqrt = math.sqrt
local component = require('component')
local geolyzer = component.geolyzer
local hologram = component.hologram

local function distance(x, y, z)
  return sqrt(x^2 + y^2 + z^2)
end

local function magic(R, H, D)
  return 2112 * (R - H) / D
end

local function visualize(hardness, elevation, size)
  hologram.clear()
  hologram.setScale(9)
  local blocks, result
  for x = -size, size do
    for z = -size, size do
      blocks = geolyzer.scan(x, z, elevation, 1, 1, 32)
      for i_y = 1, 32 do
        result = magic(blocks[i_y], hardness, distance(x, i_y+elevation-1, z))
        if blocks[i_y] ~= 0 and result > -128 and result < 127 and (result%1 > 0.9998 or result%1 < 0.0002) then
          hologram.set(x+24, i_y, z+24, true)
        end
      end
    end
  end
end

local hrd, ele, siz = table.unpack({...})
hrd = hrd or 3
ele = ele or -32
siz = siz or 16
visualize(hrd, ele, siz)

l3rb7E1.png

For a more accurate hardness determination, two scans can be taken. Move one relative to the other so that the distances with the artifacts do not coincide.

In order not to perform a heavy sqrt operation, you can create a dictionary where [x^2 + y^2 + z^2] = sqrt(x^2 + y^2 + z^2), 1742 unique values are required in total.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.