Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post Reply
Maxreader
Burner Inserter
Burner Inserter
Posts: 13
Joined: Fri Jun 28, 2019 7:44 am
Contact:

Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by Maxreader »

Greetings!

While playing around with some noise expression stuff, I came across the same issue in this post: viewtopic.php?f=25&t=83807&p=489988&hil ... ce#p489988. To illustrate what the terrace function is supposed to do given the code that was provided, see the graph of variable b in the following link: https://www.desmos.com/calculator/daav2vjkcs. Subtracting x from the result, if the "strength" is 1, gives a modulo function, which is what I desire. Of course, I ran into the same issue as mooman did, that the terrace function seemingly does not work for either of negative x or negative y, even if it does not consume that respective variable in that expression. Given below is one way to reproduce the issue, using the value of iron ore richness as a debug tool:

Code: Select all

--modulo function derived from noise.terrace()
local function modulo(val, range)
    range = range or 1
    return val - noise.terrace(val, 0, range, 1)
end

--noise expression wrapping that function
data:extend{
{
        type = "noise-expression",
        name = "new-iron-ore",
        expression = noise.define_noise_function(
            function(x, y, tile, map) return modulo(x, 32) * 100
                        end)
    }
}

--applying that noise expression to iron ore within a map preset, and allowing iron ore to always take precedence
local mgp = data.raw["map-gen-presets"].default
mgp["test-preset"] = {
    name = "fractured-preset",
    order = "z",
    basic_settings = {
        property_expression_names = {
            ["entity:iron-ore:richness"] = "new-iron-ore",
            ["entity:iron-ore:probability"] = 100
        },
    },
}
Which produces the following kind of map:
Image
As you can see, there are bands of ore, with the richness being 0 for every x value that's divisible by 32. However, the function fails for y < 0, even though y is referenced nowhere in the expression.

I request that the matter be at least given cursory investigation, and failing a solution being found there, the pure floor() function (alternatively modf()) used in the underlying c++ being made available for use.

Maxreader
Burner Inserter
Burner Inserter
Posts: 13
Joined: Fri Jun 28, 2019 7:44 am
Contact:

Re: Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by Maxreader »

As an extra interesting tidbit that points toward broken behavior, if you take the same code I posted above and set "strength" to 0, you get the following:
Image
That is to say, instead of being 0 everywhere as expected, you get nothing (maybe 0, maybe some negative number) for negative x, but still modulo for positive x.

posila
Factorio Staff
Factorio Staff
Posts: 5063
Joined: Thu Jun 11, 2015 1:35 pm
Contact:

Re: Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by posila »

Ok, I looked into it and terrace is indeed broken. Luckily it is not used in base game, so it should be safe to fix.

Maxreader
Burner Inserter
Burner Inserter
Posts: 13
Joined: Fri Jun 28, 2019 7:44 am
Contact:

Re: Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by Maxreader »

Awesome, thank you for looking into it!

Maxreader
Burner Inserter
Burner Inserter
Posts: 13
Joined: Fri Jun 28, 2019 7:44 am
Contact:

Re: Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by Maxreader »

While we're at it, if-else-chain also seems to not work correctly. Image
Is there any insight as to why, or what it actually expects on the other end? The current workaround is doing nasty "multiply by 0 or 1" type expressions like the following:

Code: Select all

local difference = pDistance - minDistance
            local clampedDifference = noise.min(difference, 0)
            local isMinimum = clampedDifference / difference
            secondDistance = secondDistance + (minDistance - secondDistance) * isMinimum
            value = value + (point.val - value) * isMinimum
            minDistance = minDistance + clampedDifference
which Factorio will eventually parse, but is rather slow.

Bilka
Factorio Staff
Factorio Staff
Posts: 2790
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Fix noise.terrace(), or expose floor() and/or modf() to noise expressions

Post by Bilka »

Noise.terrace was already fixed a few versions ago. With 0.18.37 I added floor(), modulo() and if-else-chain allows you to use variables in its conditions.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.

Post Reply

Return to “Implemented mod requests”