#development

1 messages · Page 308 of 1

wheat mesa
#

It’s a pretty big topic and I don’t really know a whole ton about it so people there might have more experience with advanced procgen

sharp geyser
#

Gotcha

#

Will find it

trim urchin
#

hello there,
I made a Discord bot called TB Tea — it lets you chat across different servers 👀
I need testers if anyone interested pingme

deft wolf
#

No thanks

swift edge
#

If I drop my bot website for public review here will it be promotion?

stark kestrel
#

If you're honest and want a review of it as kind of feedback, other people have done it - so doubt

swift edge
#

I just don’t wanna get muted for promoting

stark kestrel
#

Others did so very likely doubt

sharp geyser
#

I keep crashing studio

stark kestrel
#

Screenshots were also sent so 🤷‍♂️

sharp geyser
#

I think my terrain gen is too much 💀

swift edge
#

Sure

#

I’ll risk

stark kestrel
#

@oak cliff maybe you can confirm

swift edge
stark kestrel
#

But it's also the dev channel so yeah, makes it even more suited for feedbacks and such

oak cliff
#

as long as youre not asking people to use it and more just review how your site looks then yes thats fine

#

and you arent doing it like every day annyHeh

stark kestrel
stark kestrel
#

That's fair then

swift edge
#

Focused more on dashboard

#

Just copied templates from mui Vercel

stark kestrel
#

The rest is fine, haven't logged in, just maybe that when you switch pages you don't get scrolled back to the top

swift edge
#

Oh would fix that

sharp geyser
#

@wheat mesa tadah

#

Even has caves

#

Do I fully understand the math and techniques, no not yet but I am sure I will after studying it a bit more

lyric mountain
#

gz

sharp geyser
#

I use chunks and stuff too

lyric mountain
#

btw, for the mountain stone u can base it off the difference between 2 coordinates in the noise map

lament rock
#

Is that with marching cubes?

sharp geyser
#
function fbm(x, z, octaves, frequency, amplitude, lacunarity, persistence)
    local total = 0
    local currentFrequency = frequency
    local currentAmplitude = amplitude

    for i = 0, octaves - 1 do
        total += math.noise(x * currentFrequency, z * currentFrequency) * currentAmplitude
        currentFrequency *= lacunarity
        currentAmplitude *= persistence
    end

    return total
end

local terrain = workspace.Terrain

terrain:Clear()

local WATER_LEVEL = 10
local MAP_SIZE = 1000
local MAX_HEIGHT = 200
local CHUNK_SIZE = 64
local RESOLUTION = 4

for cx = 0, MAP_SIZE - 1, CHUNK_SIZE do
    for cz = 0, MAP_SIZE - 1, CHUNK_SIZE do
        local xSize = math.min(CHUNK_SIZE, MAP_SIZE - cx)
        local zSize = math.min(CHUNK_SIZE, MAP_SIZE - cz)

        local materials = {}
        local occupancy = {}

        for xi = 1, xSize do
            materials[xi] = {}
            occupancy[xi] = {}
            local x = cx + xi - 1

            -- pre-calculate column data for this X row
            local columns = {}
            for zi = 1, zSize do
                local z = cz + zi - 1
                local biomeNoise = math.noise(x * 0.003, z * 0.003)
                local t = (biomeNoise + 0.5)
                t = t * t
                local amp = 2 + (150 - 2) * t
                local rawHeight = fbm(x, z, 6, 0.01, amp, 2, 0.3)
                local baseHeight = 10 + (60 - 10) * t
                local height = rawHeight + baseHeight

                local mat = Enum.Material.Grass
                if height < WATER_LEVEL + 1 then
                    mat = Enum.Material.Sand
                elseif rawHeight > amp * 0.7 then
                    mat = Enum.Material.Snow
                elseif rawHeight > amp * 0.4 then
                    mat = Enum.Material.Rock
                end

                columns[zi] = { height = height, mat = mat, t = t }
            end

            for yi = 1, MAX_HEIGHT do
                materials[xi][yi] = {}
                occupancy[xi][yi] = {}

                for zi = 1, zSize do
                    local col = columns[zi]

                    if yi <= col.height then
                        local isCave = false
                        if col.t > 0.4 and yi > WATER_LEVEL + 10 then
                            local caveNoise = math.noise((cx + xi - 1) * 0.03, yi * 0.03, (cz + zi - 1) * 0.03)
                            if caveNoise > 0.45 then isCave = true end
                        end

                        if isCave then
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        else
                            materials[xi][yi][zi] = col.mat
                            occupancy[xi][yi][zi] = 1
                        end
                    else
                        if yi <= WATER_LEVEL then
                            materials[xi][yi][zi] = Enum.Material.Water
                            occupancy[xi][yi][zi] = 1
                        else
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        end
                    end
                end
            end
        end

        local region = Region3.new(
            Vector3.new(cx * RESOLUTION, 0, cz * RESOLUTION),
            Vector3.new((cx + xSize) * RESOLUTION, MAX_HEIGHT * RESOLUTION, (cz + zSize) * RESOLUTION)
        )

        terrain:WriteVoxels(region, RESOLUTION, materials, occupancy)
        task.wait()
    end
end

Well this is how I currently do it

#

I don't understand it fully, especially the whole chunking thing. I just know doing it in chunks is faster somehow

lyric mountain
wheat mesa
lyric mountain
#

make the threshold higher or lower depending on whether u want rock to appear sooner or later (lower for more stone, higher for less stone)

wheat mesa
#

You can represent each vertex within a chunk as a limited offset depending on your chunk size, and also you can offload meshing tasks and such to different threads

lyric mountain
#

can also use the steepness for stuff like tree generation to prevent trees in impossible slopes

wheat mesa
#

Also chunks make LODs easier to implement I think but not 100% sure

lyric mountain
#

for terrain LOD yeah, since you dont need to compare every single vertex with current position

sharp geyser
#

LOD?

lyric mountain
#

level of detail

wheat mesa
#

(Also makes GPU occlusion culling & frustum culling much easier)

sharp geyser
#

I see

lyric mountain
#

as in, nearer things are more detailed than the farther stuff

wheat mesa
#

That way you only have to compare the AABBs of chunks instead of block-by-block

lyric mountain
#

so you dont waste processing on things the viewer cant even notice

sharp geyser
#

Yeah I dont eve nwant to begin figuring out how to optimize this for roblox, especially when it comes to adding in prefabs, cause rn I am sure roblox will try and load everything in at once for the player

#

FPS go brrr

sharp geyser
lyric mountain
#

basically take two points in a 2d plane and check how "steep" the slope is between them

wheat mesa
#

y2 - y1 / x2 - x1

lyric mountain
#

goes from 0 (flat) to 1 (totally vertical)

sharp geyser
#

I feel like I learned this in math class

wheat mesa
#

You probably did

#

Slope of a line

sharp geyser
#

sounds like the slope formula thing

lyric mountain
#

it is

sharp geyser
#

yeah I kinda flunked math and barely paid attention, now I regret it

lyric mountain
#

that's a rlly useful formula for procgen when dealing with materials or prefab placements

#

I put abs there so u only get from 0 to 1, since you dont care whether the slope is upwards or downwards

sharp geyser
#

I fucked up

#

😭

lyric mountain
#

lmao

sharp geyser
#

I think I know why

#

im stupid

#
local WATER_LEVEL = 10
local MAP_SIZE = 1000
local MAX_HEIGHT = 200
local CHUNK_SIZE = 64
local RESOLUTION = 4

local prevX = 0
local prevHeight = 0

for cx = 0, MAP_SIZE - 1, CHUNK_SIZE do
    for cz = 0, MAP_SIZE - 1, CHUNK_SIZE do
        local xSize = math.min(CHUNK_SIZE, MAP_SIZE - cx)
        local zSize = math.min(CHUNK_SIZE, MAP_SIZE - cz)

        local materials = {}
        local occupancy = {}

        for xi = 1, xSize do
            materials[xi] = {}
            occupancy[xi] = {}
            local x = cx + xi - 1

            -- pre-calculate column data for this X row
            local columns = {}
            for zi = 1, zSize do
                local z = cz + zi - 1
                local biomeNoise = math.noise(x * 0.003, z * 0.003)
                local t = (biomeNoise + 0.5)
                t = t * t
                local amp = 2 + (150 - 2) * t
                local rawHeight = fbm(x, z, 6, 0.02, amp, 2, 0.2)
                local baseHeight = 10 + (60 - 10) * t
                local height = rawHeight + baseHeight
                
                prevX = x
                prevHeight = height
                
                local steepness = math.abs(rawHeight - prevHeight) / math.abs(x - prevX)
                

                local mat = Enum.Material.Grass
                if height < WATER_LEVEL + 1 then
                    mat = Enum.Material.Sand
                elseif rawHeight > amp * 0.7 then
                    mat = Enum.Material.Snow
                elseif steepness > amp * 0.4 then
                    mat = Enum.Material.Rock
                end

                columns[zi] = { height = height, mat = mat, t = t }
            end

            for yi = 1, MAX_HEIGHT do
                materials[xi][yi] = {}
                occupancy[xi][yi] = {}

                for zi = 1, zSize do
                    local col = columns[zi]

                    if yi <= col.height then
                        local isCave = false
                        if col.t > 0.4 and yi > WATER_LEVEL + 10 then
                            local caveNoise = math.noise((cx + xi - 1) * 0.03, yi * 0.03, (cz + zi - 1) * 0.03)
                            if caveNoise > 0.45 then isCave = true end
                        end

                        if isCave then
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        else
                            materials[xi][yi][zi] = col.mat
                            occupancy[xi][yi][zi] = 1
                        end
                    else
                        if yi <= WATER_LEVEL then
                            materials[xi][yi][zi] = Enum.Material.Water
                            occupancy[xi][yi][zi] = 1
                        else
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        end
                    end
                end
            end
        end

        local region = Region3.new(
            Vector3.new(cx * RESOLUTION, 0, cz * RESOLUTION),
            Vector3.new((cx + xSize) * RESOLUTION, MAX_HEIGHT * RESOLUTION, (cz + zSize) * RESOLUTION)
        )

        terrain:WriteVoxels(region, RESOLUTION, materials, occupancy)
        task.wait()
    end
end
#

I am assigning prevHeight and prevX right after calculating height

#

That would just do rawHeight - rawHeight no?

lyric mountain
#

prevHeight would be the rawHeight of the previously visited coordinate

sharp geyser
#

I need to set prevHeight after calulcating the steepness

lyric mountain
#

not the current coordinate

#

also, you'll need to choose what to do on the first coord, since it'll not have either information

sharp geyser
#
    local steepness = 0
                if zi > 1 then
                    steepness = math.abs(height - prevHeight)
                end
                prevHeight = height
                

                local mat = Enum.Material.Grass
                if height < WATER_LEVEL + 1 then
                    mat = Enum.Material.Sand
                elseif rawHeight > amp * 0.7 then
                    mat = Enum.Material.Snow
                elseif steepness > 3 then
                    mat = Enum.Material.Rock
                end

#

I honestly dont know what effect this had

#

It looks the same to me 😭

lyric mountain
#

note the rock walls on the mountains

sharp geyser
#

Ah yeah

#

This is very cool stuff

lyric mountain
#

now it's just a matter of finetuning

sharp geyser
#

yeah

#

I just am not sure what

#

for starters there's definitely too much water,

#

ima try changing WATER_LEVEL to a lower number

#

Does not seem to be enough

#

I want lakes, not small ponds

lyric mountain
#

you need biomes basically

#

like, the parameters u use for mountains would not be the same you use for oceans

#

to fix this, u can generate a second noise map with a much lower detail level (0 octaves) to use as a mask

#

0 being ocean, 1 being mountains, anything in-between serving as transition between them

sharp geyser
#

slow down buddy I just barely started understanding this, now we are talking about using masks

lyric mountain
#

umm, lemme draw

sharp geyser
#

😭

lyric mountain
#

for example, imagine this is your current terrain noise

sharp geyser
#

Yuh

lyric mountain
#

then u generate another at a much lower resolution (low octaves) with a different seed

#

anywhere where it's black u consider it to be ocean biome

#

where it's white u consider to be land biome

#

now during your coordinate iterator, you simply check what value it is in the "biome map"

#

if the current coordinate is 0, you use ocean parameters, if it's 1 you use land paramenters

#

anything in-between you interpolate between the two

sharp geyser
#

I think I get it

#

Let me see if I can get something working

#

oh wow

#

Isn't done generating yet but I definitely see a massive difference 💀

#
                local z = cz + zi - 1
                local biomeMap = fbm(x, z, 2, 0.002, 1, 2, 0.5)
                local t = (biomeMap + 0.5)
                t = t * t
                local amp = 2 + (150 - 2) * t
                local rawHeight = fbm(x, z, 6, 0.02, amp, 2, 0.2)
                local baseHeight = -10 + (60 - (-10)) * t
                local height = rawHeight + baseHeight
lyric mountain
#

ye, that's basically the idea

#

to make it easier to you, make a class or struct to hold the biome parameters, then add a function to return an interpolated biome

#

so you dont need to do the calcs everywhere

#

also, for the land map, add a height offset so it's always above sea level

#

instead of increasing magnitude

#

it'll get u smoother plains

sharp geyser
#

Yeah I am currently running all this in studio's command prompt 💀

#

I havent even started abstracting it yet, I know ima need to so I can always access values, especially when it comes to planting prefabs on the terrain

sharp geyser
lyric mountain
#

no, add it to height

#

basically give a heightOffset property to every biome

#

ocean would have smth negative for deep seabed

#

land would have it at heightOffset = WATER_LEVEL

sharp geyser
#

so local height = (rawHeight + baseHeight) + WATER_LEVEL ?

lyric mountain
#

for land, yes

#

this is to guarantee you dont get water in your land biome

sharp geyser
#

Hm okay

#

I think I did it correctly

#

Yeah okay

#

Resulting terrain

#

After tweaking the t and frequency of the rawHeight I got this

lyric mountain
#

nearly there :D

#

the noise you're using for the water is too small, increase its size

sharp geyser
#

Terrain is ribbed which I noticed

#

I assume its a resolution issue

lyric mountain
#

yeah, what you're seeing is the limit of 255 tones of gray

#

not exactly sure how to fix that, since I had that same problem with the texture generator I made as a graduation project

#

you'd likely use interpolation to fill the gap between pixels

sharp geyser
#

Smoother

#

I fixed it by adding an addition branch to the if statement yi

#
if yi <= col.height then
                        local isCave = false
                        if col.t > 0.4 and yi > WATER_LEVEL + 10 then
                            local caveNoise = math.noise((cx + xi - 1) * 0.03, yi * 0.03, (cz + zi - 1) * 0.03)
                            if caveNoise > 0.45 then isCave = true end
                        end

                        if isCave then
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        else
                            materials[xi][yi][zi] = col.mat
                            occupancy[xi][yi][zi] = 1
                        end
                    elseif yi - 1 < col.height then
                        occupancy[xi][yi][zi] = col.height - (yi - 1)
                        materials[xi][yi][zi] = col.mat
                    else
                        if yi <= WATER_LEVEL then
                            materials[xi][yi][zi] = Enum.Material.Water
                            occupancy[xi][yi][zi] = 1
                        else
                            materials[xi][yi][zi] = Enum.Material.Air
                            occupancy[xi][yi][zi] = 0
                        end
                    end
#

roblox allows regions to be partially occupied

#

instead of a flat 0 - 1 it can be 0.5 0.4 0.3 etc

sharp geyser
lyric mountain
#

are u adding a negative height offset to the water?

sharp geyser
#

Terrain regen made a smiley face

lyric mountain
#

lmaooo

sharp geyser
#

anyways

lyric mountain
#

why's it crying

#

🥲

sharp geyser
#

Cause its reflecting the person writing the code

#

Water reflects 🥁

#

anyways

#

yes I am

#
local biomeMap = fbm(x, z, 2, 0.001, 1, 2, 0.5)
                local t = (biomeMap + 0.5)
                t = t * t * t
                local amp = 2 + (150 - 2) * t
                local rawHeight = fbm(x, z, 6, 0.01, amp, 2, 0.2)
                local baseHeight = -10 + (60 - (-10)) * t
                local heightOffset = WATER_LEVEL + 5
                local height = rawHeight + baseHeight + heightOffset
#

messing with the -10 value in baseHeight does modify it

#

HES BACK

lyric mountain
#

gotta find why the smiley appeared lul

stoic bough
#

Leave him in as an Easter egg somewhere

#

Once u do find it

sharp geyser
#

It isn't in the final result

#

Its the terrain being cleared then regened

lyric mountain
#

ah

sharp geyser
#

What am I missing

#

I dont understand

#

-10 -> -5

#

but anything lower than -10 and I might as well released noahs ark

lyric mountain
#

like, it wasnt supposed to have water in the land biome since the height would never go below 0

#

oh wait

#

your -10 is the seabed level

sharp geyser
#

yeah

#

I dont understand how this math works

lyric mountain
#

basically, the height offset for water should be smaller than 10 (so it doesnt cancel the seabed level)

sharp geyser
#

it is smaller

#

its 8

lyric mountain
#

u can make it 0 for water

#

for land try putting 11

sharp geyser
#

I don't do any different offsets

lyric mountain
#

u should lul

sharp geyser
lyric mountain
#

that's why I mentioned putting it into the biome class

sharp geyser
#

Im too stupid for this bro

lyric mountain
#

for water the offset can be 0 without problem, but for land it must always be bigger than sealevel (in this case 10)

#

to make sure land is always above water

sharp geyser
#

I don't even have this abstracted out btw, I am running this all in terminal

#

😭

lyric mountain
#

ur a madlad

sharp geyser
#

Right

#

so

#

rawHeight is my noise for the terrain, and biomeMap is my noise for water right?

#

so i'd offset those 2 ?

#

guess not

#

💀

stoic bough
#

Looks like a typical midwest setting

#

Snow AND land at the same time

sharp geyser
#

proc gen is annoying

#

too much math

#

At the risk of blowing my pc up

#

im generating a 3000x3000 map

#

💀

#

yeah 3000x3000 made fans go brr, I wonder if I can further improvde this terrain gen, I will think about that when I start abstracting this into a module to reuse

lyric mountain
sharp geyser
#
                local z = cz + zi - 1
                local biomeMap = fbm(x, z, 2, 0.001, 1, 2, 0.5)
                local t = (biomeMap + 0.5)
                t = t * t
                local mountainT = math.max(t - 0.5, 0) * 2
                local amp = 2 + (150 - 2) * mountainT
                local rawHeight = fbm(x, z, 6, 0.01, amp, 2, 0.2)
                local baseHeight = -5 + (60 - (-5)) * t
                local heightOffset = 0 + (WATER_LEVEL + 10) * t
                local height = rawHeight + baseHeight + heightOffset
#

It's not perfect but

#

its damn good

lyric mountain
#

The important part is to ensure land's rawHeight never goes below WATER_LEVEL

#

And that sea's never go above

#

Unless u want isles

#

By adding the offset you're nullifying the negative height that makes it go underwater

sharp geyser
lyric mountain
#

Basically, the blackest area in land's noise map must be above sea

lyric mountain
sharp geyser
lyric mountain
#

Oh, that's what t is for?

#

The interpolation factor?

sharp geyser
#

That’s what I assumed?

#

Yeah

#

So biomes blend smoothly

lyric mountain
#

Nvm then, didn't notice

sharp geyser
#

Instead of a hard cutoff

lyric mountain
#

Usually we call it fac so I ignored it subconsciously

sharp geyser
#

Ah

#

Yeah idk I used Claude for the initial code I won’t lie

#

Then I kept tweaking and trying to figure stuff out

#

And I’m just too stupid in maths

lyric mountain
#

Now, just so u can debug, make grass red where it's supposed to be water biome

#

Or just use some different texture

#

I believe there's water inside those mountains cuz they're inside water biome

sharp geyser
#

There is not water in it from what I can see

#

Water is only put in specific places

sharp geyser
#

It's meant to be there based off the noise generated

lyric mountain
#

But if that's a land biome, it shouldn't have water no?

sharp geyser
#

Not necessarily no?

#

the first map defines a noise on where land and water should go, that basically is like a little pond with land around it

lyric mountain
#

Well, if it's intentional then it's fine

sharp geyser
#

I mean idk if its intentional but that seems to be what the math is supposed to do

#

😭

#

Hmmm i wonder how you enter this cave mmLol

lyric mountain
#

Lul how did that even happen

sharp geyser
#

I assume it's the cave portion of the code

lyric mountain
sharp geyser
#

Then ig its not right, idk man proc gen is getting confusing asf there's too much numbers involved

#

I can't follow it at all

lyric mountain
#

U get used to it after a while

#

Like, think about it like this:
The height map (first noise) generates a value between 0 (black) and 1 (white), water level is at height = 0

#

So for land biome, the height would be WATER_LEVEL + value

#

And for water biome it'd be WATER_LEVEL - depth + value

#

As in, only water biome would ever go below water level

sharp geyser
sharp geyser
lyric mountain
#

yes, that's why I was confused as to why there's water there

sharp geyser
#

Idk

#

I couldn’t tell you lmaoo

lyric mountain
#

wait, why are u doing t = t * t?

#

the value returned by biomeMap should be enough on its own

sharp geyser
#

Because the land was too hilly /mountainous

#

There was no flat plains

#

So I’m squaring it

#

It gives me a smaller amplitude

#

So it’s not as hilly at lower t values

lyric mountain
#

that's a issue on mountainT's side, t is supposed to be the raw value from biomeMap

#

like, that's the "slider" between water and mountain

wheat mesa
#

Can't believe you guys have been going at this for this long lol

#

Most dedicated helper oat award

lyric mountain
#

waffle, come help too lul

wheat mesa
#

I'm not good at procgen :c

#

I haven't gotten that far in my engine yet

lyric mountain
#

but u know math >.>

wheat mesa
#

A lil bit

lyric mountain
#

we trying to figure out why there's water inside the mountains up there

lyric mountain
wheat mesa
#

I mean is it possible that the biome noise just happens to put water there

#

It might be good to plot the actual biome map

sharp geyser
#

That’s what I was thinking

lyric mountain
#

due to height offset, it'd not be possible to have the noise go below water

sharp geyser
#

Squaring t made flatter terrain more common

wheat mesa
#

What does t represent

lyric mountain
#

it's the fac value

#

interpolation factor

sharp geyser
#

^

wheat mesa
#

So yeah squaring it would make it smaller, anything x^2 < x for 0 < x < 1

lyric mountain
wheat mesa
#

So between 0 and 1

#

What's the point of adding 0.5 to it?

#

Also what does local baseHeight = -10 + (60 - (-10)) * t represent here? Why not simplify to 60 * t

sharp geyser
#

I think it’s leftover from before the secondary map where it returned -0.5 and 0.5 so it was a flat 0-1

#

This code is all over the place mind you

wheat mesa
#

I don't really know what each variable represents atm so it's a bit difficult for me to read & catch up

sharp geyser
#

When I’m home I’ll try and help more 😭

#

I had to leave temporarily to the store

wheat mesa
#

I'm gonna leave in like 45 mins from work so I won't be able to help then probably but I'm sure @lyric mountain knows how to help lol

#

also this is completely unrelated but I've been researching transformers and the math behind them is so amazingly ingenius that I have no idea how a human came up with this

sharp geyser
#

Okay I can’t send my message cause of an automod filter

#

Welp

#

I’m cooked

deft wolf
delicate zephyr
#

Lmao aaron

sharp geyser
#

I was about to tell you what each variable meant

delicate zephyr
#

👏

sharp geyser
#

😭

delicate zephyr
#

send the paragraphs individually

sharp geyser
#

LOOK Claude made the code it can explain its own hallucinations

delicate zephyr
#

and remove the emdashes

sharp geyser
#

I’m on phone

#

Too much work

delicate zephyr
#

Oh oof

sharp geyser
#

biomeMap A noise value that determines what type of terrain this location is. Uses low octaves (2) and low frequency (0.001) to create large, smooth biome regions. Returns roughly -0.5 to 0.5.

#

t The biome value normalized to 0-1 range. Adding 0.5 shifts from [-0.5, 0.5] to [0, 1]. Then squaring (t * t) biases it so most of the map gets low values (plains/ocean) and only peaks become high values (land/mountains). This drives the land/ocean split and terrain elevation.

#

mountainT A modified version of t that only activates for mountains. Subtracting 0.5 means any t below 0.5 becomes negative, and math.max clamps that to 0. Multiplying by 2 rescales the 0.5-1.0 range back to 0-1. Effect: t values 0 to 0.5 produce mountainT = 0 (flat, no mountains). Only t above 0.5 starts producing mountains. This separates “land vs ocean” from “flat vs mountainous.”

#

amp The amplitude for the terrain noise, driven by mountainT. When mountainT = 0 (most of the map), amplitude is 2, barely any height variation, flat plains. When mountainT = 1 (rare peak biome regions), amplitude is 150, dramatic mountain peaks. This is why mountains only appear in certain areas.

rawHeight The actual terrain shape from the main fbm noise. Uses 6 octaves for detail, frequency 0.01 for medium-sized features, and persistence 0.2 for smooth results. The amplitude (amp) controls how tall this noise is allowed to be. In plains, rawHeight swings maybe -1 to 1. In mountains, it swings -75 to 75.

#

baseHeight The ground floor elevation, driven by t. Lerps from -5 (ocean biome) to 60 (land biome). This sets the starting elevation before noise adds variation on top. Ocean areas sit below water level. Land areas sit well above. The coastline forms at the transition.

heightOffset Extra elevation boost driven by t. Lerps from 0 (ocean) to WATER_LEVEL + 10 (land). This guarantees land areas are always above water level. Ocean areas get no boost, staying below water. Combined with baseHeight, this creates the land/ocean separation.

#

height The final terrain surface level at this point. Three things added together: the noise-generated shape (rawHeight), the biome-driven ground floor (baseHeight), and the water protection boost (heightOffset). This is what the Y loop compares against to decide if a voxel is solid, water, or air.​​​​​​​​​​​​​​​​

#

@wheat mesa there that’s Claude’s hallucinations and barbaric reasonings for the variables existing

sharp geyser
#

NO

lyric mountain
#

luke's turn

sharp geyser
#

Fuck proc gen

#

I’m trashing this entire idea I hate math

wheat mesa
#

math is great

#

if you're doing game dev then this math is the easy part lol

sharp geyser
#

Not when you don’t understand math

#

I feel stupid and I hate that val_Sadge

wheat mesa
#

The math itself isn't crazy confusing, it's how to apply it in a way that gives the results you want that's confusing

#

So don't feel bad if it's tough to understand, you never get good at something without first being bad at it

trail sand
#

helpppp

wheat mesa
#

I don't even understand this stuff and I'd say I have a decently strong math background

sharp geyser
#

Ima try and do more reading online

wheat mesa
#

Rome wasn't built in a day

queen needle
#

not yet™️

neon leaf
#

the most cursed yet incredible thing ive seen this week

sharp geyser
#

What in gods green earth is this

wheat mesa
#

It’s saying that given inputs x and y this is how you mathematically compute the value of fbm(x, y)

sharp geyser
#

What's that weird E

wheat mesa
#

That’s Sigma, it’s summation

sharp geyser
#

also whats with n-1 and i=0 above and below it

wheat mesa
#

It means sum from i = 0 to i = n - 1

#

It’s like a for loop

sharp geyser
#

I see

#

so go until i is equal to n - 1?

wheat mesa
#

Yes, and including i = n - 1

#

[0, n-1]

#

Basically

sum = 0
for i = 0 to i = n-1:
    sum += noise(x * f[i], y * f[i]) * a[i]
sharp geyser
#

hm interesting

#

I've seen so many methods of doing fBM

#

that i have no idea which is correct

#
function fBm(x, z, octaves, persistence, lacunarity, scale)
    local total = 0
    local amplitude = 1
    local frequency = 1
    local maxValue = 0  -- Used for normalizing

    for i = 0, octaves do
        -- Use math.noise for Perlin Noise
        total = total + math.noise(x * frequency / scale, z * frequency / scale) * amplitude
        
        maxValue = maxValue + amplitude
        
        amplitude = amplitude * persistence
        frequency = frequency * lacunarity
    end
    
    return total / maxValue -- Normalize between -1 and 1
end

-- Usage for height:
local height = fBm(x, z, 4, 0.5, 2, 100) * maxHeightMultiplier

Like this is rather different then what I had, and what i've seen

#

they normalize it ig

wheat mesa
#

This looks pretty much exactly like what that mathematical function does with some slight modification

sharp geyser
#

yeah it divides instead of multiplying

wheat mesa
#

But yeah typically it’s useful to normalize between 0 and 1

sharp geyser
#

I dont get it

#

it says it normalizes

#

but I am still getting floats

wheat mesa
#

Normalizing means that it’s a decimal point scaled between two values

sharp geyser
#

Oh

wheat mesa
#

Usually it’s either -1 and 1 or 0 and 1

sharp geyser
#

yeah I knew that heh

#

I was testing you

wheat mesa
#

Very common practice in ML, I think it’s pretty normal (no pun intended) in procgen too

#

Just more convenient to work with

sharp geyser
#

yeah that makes sense

#

working with a known range is a lot easier than a unknown

wheat mesa
#

Yeah it’s nice to know the range of values you can expect

sharp geyser
#

Alright so I for the most part understand fBM

#

but not how to apply it

#

back to the virtual books

sharp geyser
#

@lyric mountain right so local biomeNoise = WATER_LEVEL - 10 + fbm(x, z, 2, 0.5, 2.0, 100) is this what you meant when you were talking about an offset? figured out thats not what you meant

sharp geyser
#

Well v1 is a bust

stoic bough
#

looks like no mans sky

hard zenith
#

Been working on a small project. An inspired discord bot game of Discord Scream 7 orb quest! T_cutepls

sharp geyser
#

Alright iteration 3 produces this

#

omg bro

#

I am so tired of discord

sharp geyser
#

iteration 4

#

increased the scale in rawHeight and upped the landHeight addition from 5 -> 10

#

This is very close to my desired outcome

lyric mountain
#

I'm back

#

That one render is cute

sharp geyser
#

I got a good result

#

I also broke down the terrain gen code into it's own module that also caches chunks

#
type ColumnData = {
    height: number,
    mat: Enum.Material,
    t: number,
    mountainT: number,
    steepness: number,
    rawHeight: number,
    biomeNoise: number,
}
type ChunkData = { columns: { [string]: ColumnData } }

-- chunks[x][z]
type TerrainModule = {
    chunks: { [string]: ChunkData },
    generateChunk: (self: TerrainModule, cx: number, cz: number) -> ChunkData,
    getColumnAt: (self: TerrainModule, worldX: number, worldZ: number) -> ColumnData | nil,
    getChunk: (self: TerrainModule, cx: number, cz: number) -> ChunkData,
    CHUNK_SIZE: number,
    WATER_LEVEL: number,
    RESOLUTION: number,
    MAP_HEIGHT: number,
    MAP_SIZE: number,
}
sharp geyser
#

@lyric mountain hazaahhh

#

chunk spawning / despawning works

#

Still a bit laggy

#

Not sure how to really fix that hm

#

The fps drops to like 1 for 20-30s on initial load

high gale
#

how often do mod checks tickets?

stark kestrel
high gale
stark kestrel
#

they have school, jobs, families, etc.

#

digital moderation obviously doesn't take precedence

deft wolf
#

That's why we should implement AI to handle tickets aok

#

The response would be useless but at least it would be quick

stark kestrel
deft wolf
deft wolf
#

Maybe, maybe not

lyric mountain
wheat mesa
#

Chunk generation and meshing is generally quite expensive

earnest solar
#

Ok

#

Thx

sharp geyser
#

I might be able to make it faster idk

wheat mesa
#

Making it faster is one thing but the threading isn't optional for this if you want good visual performance

#

It's pretty much the widely accepted solution in procgen games

lyric mountain
#

use a divide-and-conquer method for generating the chunks

#

like, let's say u have 1000 chunks to generate, and your minimum allowed split value is 100 chunks per task

#
1000 chunks -> split into 4 tasks
  250 chunks -> split into 4 tasks
    62 chunks
    62 chunks
    63 chunks
    63 chunks
  250 chunks -> split into 4 tasks
    62 chunks
    62 chunks
    63 chunks
    63 chunks
  250 chunks -> split into 4 tasks
    62 chunks
    62 chunks
    63 chunks
    63 chunks
  250 chunks -> split into 4 tasks
    62 chunks
    62 chunks
    63 chunks
    63 chunks
#

now you spawn N threads and pass the tasks to them

wheat mesa
#

I just have a thread pool and pass chunk generation tasks

lyric mountain
#

then after processing you merge them back into a single result

lyric mountain
wheat mesa
#

I have a thread pool since I dynamically procgen chunks as the camera moves

lyric mountain
#

I use the DnQ method for generating my game's image, since it's a bigass jpg

#

just split into smaller pieces and let threads work on them separately, then stitch back the results

sharp geyser
#

I am not sure if roblox allows actual multi-threading

#

which

#

it seems it does

#

Parallel Luau

fierce orbit
#

This is what I am working on

#

Command previews for my commands

sharp geyser
#

@lyric mountain @wheat mesa didn't even touch parallel luau and I managed to make my system way faster

#

load times went from ~44s to ~11s

#

I just cut out useless calculations, If it's over a certain height then it's all air, no need to build any 3D arrays or calculations for it.

lyric mountain
sharp geyser
#

Yeah

#

but uh

#

I fucked it up again so that reduction went out the window

#

I wanted to push the limit further

#

Seems like if I want to do that I need to make more optimizations or just dive into parallel luau which is a concept I have 0 knowledge on

lyric mountain
#

time for a documentation dive :D

#

only lua I ever used was starbound modding and programable mouse

sharp geyser
#

I made all the optimizations I can think of

#
local jecs = require("@packages/jecs")

local terrain = require("@server/terrain")

local components = require("@shared/components")

local RENDER_DISTANCE = terrain.RENDER_DISTANCE
local DESPAWN_DISTANCE = RENDER_DISTANCE + 3

local generationQueue = {}
local queuedSet = {}

local loadedChunks = {}

local shouldExist = {}

local scanTimer = 0

local function terrain_system(world: jecs.World)
    scanTimer += 1

    if scanTimer >= 30 then
        scanTimer = 0
        shouldExist = {}
        for _, player in world:query(components.Player):iter() do
            local character = player.Character
            if not character then
                continue
            end
            local rootPart = character:FindFirstChild("HumanoidRootPart") :: BasePart | nil
            if not rootPart then
                continue
            end

            local cx, cz = terrain:worldToChunk(rootPart.Position.X, rootPart.Position.Z)
            for dx = -RENDER_DISTANCE, RENDER_DISTANCE do
                for dz = -RENDER_DISTANCE, RENDER_DISTANCE do
                    local chunkCX = cx + dx * terrain.CHUNK_SIZE
                    local chunkCZ = cz + dz * terrain.CHUNK_SIZE
                    local key = chunkCX .. "," .. chunkCZ

                    if not terrain:getChunk(chunkCX, chunkCZ) and not queuedSet[key] then
                        queuedSet[key] = true
                        table.insert(generationQueue, { chunkCX, chunkCZ })
                    end
                end
            end

            for dx = -DESPAWN_DISTANCE, DESPAWN_DISTANCE do
                for dz = -DESPAWN_DISTANCE, DESPAWN_DISTANCE do
                    local chunkCX = cx + dx * terrain.CHUNK_SIZE
                    local chunkCZ = cz + dz * terrain.CHUNK_SIZE
                    local key = chunkCX .. "," .. chunkCZ
                    shouldExist[key] = true
                end
            end
        end
    end

    local despawnCount = 0
    for key, coords in pairs(loadedChunks) do
        if not shouldExist[key] then
            terrain:despawnChunk(coords[1], coords[2])
            loadedChunks[key] = nil
            despawnCount += 1
            if despawnCount >= 2 then
                break
            end
        end
    end

    local frameBudget = 0.01
    local frameStart = os.clock()
    while #generationQueue > 0 and (os.clock() - frameStart) < frameBudget do
        local coords = table.remove(generationQueue, 1)
        local key = coords[1] .. "," .. coords[2]
        queuedSet[key] = nil
        terrain:generateChunk(coords[1], coords[2])
        loadedChunks[key] = coords
    end
    -- for _ = 1, math.min(budget, #generationQueue) do
    --     local coords = table.remove(generationQueue, 1)
    --     local key = coords[1] .. "," .. coords[2]
    --     queuedSet[key] = nil
    --     terrain:generateChunk(coords[1], coords[2])

    --     loadedChunks[key] = coords
    -- end
end

return {
    system = terrain_system,
}
lyric mountain
#

single thread can only do so much, eventually multi is a must

sharp geyser
#

This is probably the most expensive part besides the actual generateChunk call

lyric mountain
#

a thing u can do, is create all variables at start

#

then simply reassign them

sharp geyser
#

yeah but that wouldn't offer much performance benefits in the grand scheme of things

#

but I will do that for sure

lyric mountain
#

and iirc lua uses dynamic typing, so try to be as unambiguous as possible

#

if u can use static types do use them

lyric mountain
#

since it doesnt need to allocate space in loops

sharp geyser
#

fair

wheat mesa
#

Chunk generation is inherently expensive enough to cause visual stutters, threading is pretty much a requirement

#

It’s useful to have thread pools available for other work too

sharp geyser
#

the average time for the math is like ~70-80ms while the WriteVoxels call is like ~16ms avg

lyric mountain
#

oh btw

sharp geyser
#

I can do all the math in parallel luau and call WriteVoxels with the returned arrays outside of it

lyric mountain
#

whenever possible, use integers

wheat mesa
#

Keep in mind that you get 16.6ms of work per frame to maintain 60fps 😉

lyric mountain
#

int math is much faster than floating math

sharp geyser
#

There's so many rules to parellel luau

#

I basically have to redo everything

#

I know it will all be worth it

#

this idea is worth seeing if it will work

lyric mountain
#

u can do ittt

sharp geyser
#

ngl

#

ima use claude heavily idc

#

💀

#

It can decipher those docs better than I can

sharp geyser
#

@lyric mountain @wheat mesa alright I got parallel luau working

#

Load times are even faster

#

It takes about 5s

#

With an additional 5-10s of fps dropping not sure what causes that, maybe the chunk loader?

#

Initially I only render a 6 chunk radius around the player so they have something to spawn in, the chunk loader will load an additional x chunks depending on the render distance set in this case it should load an extra 6 chunks

wheat mesa
sharp geyser
#

IT's definitely the chunk loader loading in the rest of the chunks

#

but I still offload the actual math to a separate thread

#
local jecs = require("@packages/jecs")

local terrain = require("@server/terrain")

local components = require("@shared/components")

local RENDER_DISTANCE = terrain.RENDER_DISTANCE
local DESPAWN_DISTANCE = RENDER_DISTANCE + 3

local generationQueue = {}
local queuedSet = {}

local loadedChunks = {}

local shouldExist = {}

local scanTimer = 0

local function terrain_system(world: jecs.World)
    scanTimer += 1

    if scanTimer >= 30 then
        scanTimer = 0
        shouldExist = {}
        for _, player in world:query(components.Player):iter() do
            local character = player.Character
            if not character then
                continue
            end
            local rootPart = character:FindFirstChild("HumanoidRootPart") :: BasePart | nil
            if not rootPart then
                continue
            end

            local cx, cz = terrain:worldToChunk(rootPart.Position.X, rootPart.Position.Z)
            for dx = -RENDER_DISTANCE, RENDER_DISTANCE do
                for dz = -RENDER_DISTANCE, RENDER_DISTANCE do
                    local chunkCX = cx + dx * terrain.CHUNK_SIZE
                    local chunkCZ = cz + dz * terrain.CHUNK_SIZE
                    local key = chunkCX .. "," .. chunkCZ

                    if not terrain:getChunk(chunkCX, chunkCZ) and not queuedSet[key] then
                        queuedSet[key] = true
                        table.insert(generationQueue, { chunkCX, chunkCZ })
                    end
                end
            end

            for dx = -DESPAWN_DISTANCE, DESPAWN_DISTANCE do
                for dz = -DESPAWN_DISTANCE, DESPAWN_DISTANCE do
                    local chunkCX = cx + dx * terrain.CHUNK_SIZE
                    local chunkCZ = cz + dz * terrain.CHUNK_SIZE
                    local key = chunkCX .. "," .. chunkCZ
                    shouldExist[key] = true
                end
            end
        end
    end

    local despawnCount = 0
    for key, coords in pairs(loadedChunks) do
        if not shouldExist[key] then
            terrain:despawnChunk(coords[1], coords[2])
            loadedChunks[key] = nil
            despawnCount += 1
            if despawnCount >= 2 then
                break
            end
        end
    end

    local frameBudget = 0.01
    local frameStart = os.clock()
    while #generationQueue > 0 and (os.clock() - frameStart) < frameBudget do
        local coords = table.remove(generationQueue, 1)
        local key = coords[1] .. "," .. coords[2]
        queuedSet[key] = nil
        terrain:generateChunk(coords[1], coords[2])
        loadedChunks[key] = coords
    end
end

return {
    system = terrain_system,
}
#

generateChunk offloads it to a separate worker

wheat mesa
#

Could be some warmup from the editor, I know quite a few Roblox games tend to lag when you first load in

#

Seems like after that stutter is done everything is fine, including when you load new chunks so no big deal there

sharp geyser
#

Yeah

#

one thing I am seeing

#

ecs is failing

#

Somehow my server ecs is not replicating what it needs to the client

sharp geyser
#

it was the terrain system

#

from what I can tell it's running on chunks that aren't cached yet so it's having to re-do the math for it in the main thread, which is fine if a player exists chunks that need to be despawned to spawn new ones, but not for pre-gen

#

I added a guard to hopefully stop the system from running if the pre-gen terrain isn't ready yet

#

and hazaahh it significantly reduces the initial lag

eternal osprey
#

first time setting up a NAS

#

i am excited

exotic parcel
eternal osprey
#

i want to turn it into a homelab

#

and pack it with some nice features to help my development processes. Any suggestions?

#

I was thinking about my own 'github' instance

eternal osprey
#

@oak cliff

deft wolf
#

Woah

stark kestrel
#

Gitea, Sourcehut or GitLab are nice

neon leaf
#

if you nas has less than 16gb of ram do not install gitlab 👍

eternal osprey
#

mine has 16gb 🙂

sharp geyser
#

docker

#

upgrade the ram /j

eternal osprey
#

gitea is nice tho

stark kestrel
neon leaf
#
c80c6c40d832   rjns-git_job                           0.07%      22.04MiB / 503.5GiB   0.00%     0B / 0B           2.36MB / 565kB    33 
4d58e0e7fdcc   rjns-git_web                           10.41%     30.92GiB / 503.5GiB   6.14%     1.2GB / 213MB     36.5MB / 4.96GB   1610 
1f6a4bf61c6a   rjns-git_db                            0.00%      315.6MiB / 503.5GiB   0.06%     188MB / 510MB     19.8MB / 403MB    79 
#

i guess depends on usecase

#

but gitea should be sufficient for most things

eternal osprey
#

what do yall use the NAS for. Like what tools would be crucial for a nice homelab

stark kestrel
#

yah

eternal osprey
#

cuz next to gitea i am kinda stuck lmao

stark kestrel
#

then you maybe don't need one ;)

eternal osprey
#

too bad i already bought one

stark kestrel
#

there are lots of things you can deploy for your own stuff

#

i mainly have a few tools and that's about it

#

but currently offline because not many use cases

#

maybe a few later, e.g. some 5GC network 🤣

#

but would need antennas

sharp geyser
#

use it to run docker containers

neon leaf
#

buzzword detected

sharp geyser
eternal osprey
#

i actually wantto run my own infiscal instance

sharp geyser
#

I mean thats the only usecase i'd have for it

#

run my dev docker containers

#

or like jellyfin

#

or something

eternal osprey
#

but that means i need to use wireguard for it to connect to my server

#

that's hosted at datalix lmao

sharp geyser
#

Rather have a dev postgres env then put it on my prod server

#

note to self restart my pi-hole frequently

#

apparently it went down for a while now 💀

stark kestrel
#

adguard home poggythumbsup

sharp geyser
#

yeah but only my devices

#

everyone else roams with ads

neon leaf
#

i dont even use adguard to block anything

#

i just use it for caching and analytics

#

hmm

stark kestrel
#

yeah i mean some ads are on the same domain so dns blocking won't be of much use

#

youtube is the perfect example

neon leaf
#

yeah i just use brave on all the pcs i manage

sharp geyser
#

yeah pi-hole wont block youtube

stark kestrel
#

i read some time ago that they're maybe pseudo working on making it proxy as well

eternal osprey
#

I hate hate the internet

#

i wish we could go back to sticks and stones

stark kestrel
#

which would solve those issues

neon leaf
#

they could embed it directly into the video stream

#

and intentionally slow the max dl rate down

#

so you literally cannot skip

eternal osprey
#

think about it, no hackers, no trackers

#

none

stark kestrel
#

no tech

neon leaf
#

thats what a homelab allows you

#

except the no tech part

#

one of my friends has legally aquired 1.2PB of movies and audio 😄

#

no need to pay for any subscriptions

stark kestrel
#

never paid any so far ✌️

eternal osprey
#

i accidentally found that i pushed a bunch of ds_store files to github..

#

are they sensitive in any sense?

spark flint
#

no

#

they just expose path names

#

so just dont leak it online on a website as that can be used to find internal files

eternal osprey
#

ohh no it's just my local mac

#

so the DS store files are from my mac

#

hollup though my path names??

#

that's crazy

sharp geyser
#

@wheat mesa @lyric mountain

#

Guess who has procedural terrain AND procedural resources

#

😎

#

Right now they stay loaded in even if the chunk isn't but thats another time's problem

queen needle
#

Now make Minecraft

wheat mesa
sharp geyser
sharp geyser
#

I am working on the despawning of entities rn

queen needle
#

What are you making

sharp tiger
#

How can we make it where when users vote it gives them a voter role

sharp tiger
sharp geyser
sharp geyser
queen needle
#

Awesome

sharp geyser
#

They can form their own territories, kingdoms, economy, etc etc

#

I've been sitting on this idea for a while

#

Kinda want to see what people do with it

#

Wars or peace mmLol

#

The world is theortically infinite as well so long as roblox doesn't shit itself

#

Likely going to have to offload data storage of the world to an external db cause I doubt datastores will be enough to store all that data on the world.

queen needle
#

Sounds awesome

sharp geyser
#

Yeah

queen needle
#

can't wait to see your progrss

sharp geyser
#

I will need to do heavy modifications on the proc gen to make it more stable but rn it's actually not bad

#

IT only stutters when new terrain is loaded and that's really only because trees are being rendered as well

#

otherwise it'd be smooth asf

#

I've also just implemented chunk despawning, which also handles despawning any entities in the chunk as well

sharp geyser
#

I don't know how far I will get with this

#

especially with this being a side project

#

Ima need to start focusing on my main project again soon but this has just been so fun

queen needle
#

What is your main project?

sharp geyser
#

marketplace app

#

MVP is almost done im just dragging it out cause sadly lazy

#

Ima need to kick my butt back into gear soon though. The company is formed and everything so now its just about launching it

queen needle
#

That's fair

#

I have an idea I just need to not be lazy and negate AI use

sharp geyser
#

Lmaooo

#

I used ai for my proc gen

#

I’d never know the math otherwise

queen needle
#

well mine isn't anything I don't know/someone couldn't do by just reading basic instructions

lyric mountain
sharp geyser
#

Player falls through the map, and I seriously can't figure out why it's spawning the player in so early

eternal osprey
#

i am trying to setup my firewall why the fuck does synology not allow it

#

lmao subnet mask was 24

#

that 5 was a typo

#

still doesn't work tho]

#

well this did lol

lyric mountain
#

like, u dont (and shouldnt) need to wait for every chunk update, but u must wait for the very first terrain gen

neon leaf
#

the prefix is a number from 0-32, usually deliminated with a /

neon leaf
eternal osprey
#

my dsm is giving me fucking problems saying that the website is not secure due to a self-signed certificate

#

is there any way i can fix this or is this fine?

#

Planning to use it on local network only

sharp geyser
sharp geyser
#

At this point im at a loss on what to do

#

I've added long delays, and they still fall through the terrain initially

sharp geyser
#

I finally fixed it but I don’t think it’s the most elegant solution

eternal osprey
#

Installed pihole, gitea

#

Lets go

#

This nas is so fun

lyric mountain
#

like, have a variable that is only set to true after everything is done

#
local init = false -- on global context

...
thread work
...
init = true
frosty gale
sharp geyser
#

But the problem was that while it was done it was asynchronous so that doesn’t mean it’s truly done

#

I had to yield the thread for like 3s before marking it ready

#

To give Roblox enough time to fully write the voxels

#

I wish Roblox exposed a method that would yield on its own until it’s done processing the voxel writes but alas that’d be too easy

#

lowkey considering swapping to fuckin unity atp it’d save me the headache but I cba

lyric mountain
#

can u do raycasts?

#

if yes, u can emit a raycast with minimal length in every voxel coordinate, if the collision returns true then it has spawned

eternal osprey
#

Gimme another app to install on my nas

#

So far i got a local notion/trello dupe, mysql,gitea

neon leaf
#

🧠

small plover
#

Does anyone know why my bot’s profile picture is not appearing on its Top.gg page all of a sudden?

swift edge
#

Wait for few hours

small plover
#

Funny enough despite having this issue for nearly a week it seemed to fix itself right when I asked about it

warm surge
swift edge
#

they are working pretty well on compliance

warm surge
#

huh damn

frosty gale
#

but first before they can fix this the tc39 community needs to have 6 months worth of discussion around it

prisma apex
#

how to remove status from bot?

high gale
#

What's the correct API hostname and endpoint to fetch bot stats (votes, server count) using a token? I'm using Node.js https.request and keep getting a 404 HTML page from your Next.js frontend regardless of what hostname I try (top.gg, api.top.gg). The docs show GET /v1/projects/@me — what's the actual base URL for that?

deft wolf
#

You can click "Copy URL" button to copy the url

#

But looks like it doesn't contain any info about server count and votes variable is just a number

high gale
high gale
#

maybe api doesnt support those fields?

high gale
warm surge
high gale
#

oh

#

so nothing for those right?

warm surge
high gale
#

no way to get them right

warm surge
high gale
#

oh

#

i mean that works too lol

#

ight tysm!

warm surge
#

your welcome

swift edge
high gale
#

oh

eternal osprey
#

my NAS dockers are running on http.

#

How would i make them run in https lol?

#

Like i know certificates and shit, but my NAS is purely local.

#

but even then i don't trust it to leave the traffic unencrypted.

digital swan
#

use tailscale

#

it wont be https but it'll be encrypted

eternal osprey
#

tailscale?

delicate zephyr
#

And install it to your local cert store on the devices you connect to it with

eternal osprey
#

Yeah I figured

#

Tailscale seems fun but i absolutely don’t want to expose the nas

#

To the internet

sharp geyser
#

@lyric mountain So I stepped it up a bit and im using Unity now

#

Terrain is so much easier

eternal osprey
warm surge
#

@knotty night sorry mass ping im just showing where's its at

lyric mountain
#

btw, if ur using jetbrains stuff, rider has official integration with unity

sharp geyser
#

I am using rider

#

hehe

#

I will show you my most recent iteration

sharp geyser
#

My plan is having large continents with vast oceans around them that people can sail too

lyric mountain
#

Looking tundra

sharp geyser
#

Yeah still need to tweak it a tad bit

#

I want flatter plains and some prominent mountains sprinkled about

#

but its coming along rather nicely

sharp geyser
#

God no

#

Roblox would fuckin die

#

This is unity

#

I tried it in roblox and studio genuinely crashed

#

it couldn't handle it 💀

#

I say that

#

and then unity crashed

#

💀

sharp geyser
lyric mountain
#

Oooo it moves

sharp geyser
#

Yeahh

#

It uses custom shaders that I admit claude made

#

cause I have 0 clue on shaders rn

lament rock
#

Tbf, the semantics of something like hlsl is easy to grasp, but the math can get really complicated

sharp geyser
#

Yeah

#

I’m not sure on how to do any of that so I just wanted something useable for now

deft wolf
#

Who's Manu

#

This name sounds familiar

sharp geyser
#

Do you have the 1974 World Cup

hard zealot
#

I want minecraft

frosty gale
deft wolf
#

Remember this so you can expose him on twitter once his game becomes popular

edgy haven
#

i will blackmail u for that

#

hehehehehehehehe

eternal osprey
#

Okay boys i am moving over from ngrok.

#

What yall saying, caddy and reverse proxy? Or just use cloudflare tunnels?

#

its about port 3000 on localhost

#

I need to secure the endpoints such that only specific people can access it. So using ip’s, perhaps a secret

radiant kraken
#

TIL python bought an entire domain just for a function in their standard library 🙈

west knot
neon leaf
sharp geyser
frosty gale
#

i cant with the stupid shit cursor generates sometimes 😭

spark flint
#

🤣

frosty gale
#

thanks cursor i knew you were looking out for me

#

half of that response doesnt make sense but yeah

neon leaf
#

the catch (_) is wild

#

considering you can just - not have it at all and do try { } catch { }

stark kestrel
#

time to add try/catch everywhere

frosty gale
deft wolf
#

Don't forget to tell AI to do it

neon leaf
#

which is supported since nodejs 10.3

west knot
stark kestrel
#

who doesn't enjoy risky things

west knot
stark kestrel
#

for those still using docker desktop on macos

neon leaf
#

or nodejs 6.7

neon leaf
#

no more 27.0 inches 🙏 only 27

frosty gale
hard zenith
west knot
#

I'm thinking of creating a tycoon game that can be played both web-based and via Discord. What kind of game do you think I should make? The bot part should be playable via canvas screenshots, while the website part should be playable directly.

hard zenith
sharp geyser
#

Rollercoaster tycoon

#

Might be some legal issues with that though 💀

hard zenith
#

So it’s “masked killer”

spiral parrot
#

H

plush comet
eternal osprey
#

Caddu automates it

prime cliff
#

Or just use cloudlares certs

eternal osprey
#

Yeah if i use cloudflare tunnels it goes automatic

#

ma use that instead of caddy

radiant kraken
#

huaaa i forgot how heinous boost is 🙈

#

ain't no way i am waiting for an entire hour just to install a third party library

eternal osprey
#

i am using domotz to scan my network

#

for some reaosn there's a strange ass device on my network

#

can't place what it is..

#

this is suepr cool though

#

an agent on the network

frosty gale
sharp geyser
#

anyone know anything about recursive backtracking algorithm?

wheat mesa
#

What about it specifically?

sharp geyser
#

I am trying to generate a maze with rooms, corridors, dead-ends, elevation as well (so up and down).

#

There also needs to be an exit, and from what I can tell using a recursive backtracking algorithm would be the best bet

#

I have no idea how to apply constraints to it though

#

Like, making it so elevation isn't common

sharp geyser
wheat mesa
#

You probably want wave function collapse @sharp geyser

#

Procgen with "rooms" and such

sharp geyser
#

interesting

#

I will look into it

sharp geyser
sharp geyser
#

yeah I dont think WFC would work for me

#

Unless I am just misunderstanding how it would work

stoic bough
# sharp geyser Unless I am just misunderstanding how it would work

There's two kinds of WFC. An overlap model where you feed it a sample and then there's the tile model that you want. You define a set of tiles, adjacency rules like which tile sits next to which tile. Corridors connecting to stairs, dead ends etc. Then give everything a weight.

sharp geyser
#

Not to mention I’m using premade rooms

#

That wouldn’t necessarily work with WFC no?

untold flax
#

Does anyone know any good hosts? My current one has unreliable uptime which caused my bot to be rejected unfortunately 💔

copper cradle
#

how are things around here nowadays

deft wolf
sharp geyser
#

OVH is actually the cheapest rn for the performance it offers

stark kestrel
#

yippie

lyric mountain
#

at least that's how I generate my mazes

#

basically, emit a "pather" from the starting point, but have it choose a random node adjacent to it, whenever it finds a deadend have it backtract and choose a different direction

#

after it reaches the exit, emit more pathers along the way to visit the remaining unvisited nodes

frosty gale
#

sounds simple enough

jaunty mason
#

what does one do after creating a bot with 700 commands

lyric mountain
#

realise only ~50 are used and rewrite the entire thing

deft wolf
#

Delete it and start over by creating something useful instead of a kitchen sink bot

sharp geyser
jaunty mason
#

it has 752 commands

jaunty mason
jaunty mason
deft wolf
#

Yea but 700 commands is too much, considering most of it could be merged into 10-20 commands probably

#

Unless all of them are prefix commands

jaunty mason
#

i doubt it. the most u could merge it into is probably 300 if u really cramped it

jaunty mason
deft wolf
#

My god

jaunty mason
#

😭

#

i tried organizing them but uh

#

i put each command category in its own folder

#

meaning

#

it has like 50 categories now

lyric mountain
#

sussy redaction

jaunty mason
#

whats redaction

#

sorry english isnt my first language

#

😭

lyric mountain
#

the hidden category

jaunty mason
#

oh

#

find out for urself 😭

lyric mountain
#

--> ||redacted||

jaunty mason
frosty gale
sharp geyser
#

except they failed

stoic bough
#

People invite dozens of bots to avoid hundreds of commands. Thats way too many good lort

eternal osprey
#

I am finally going back to discord development

#

Will create a nice bot very soon once i get time

#

“Nice bot” this guy is such a loser

#

Thats mean 😭

mild fjord
#

Bottom = default.. O.o

west knot
jaunty mason
neon leaf
#

@delicate zephyr

deft wolf
#

Good automod rules 👍

alpine relic
#

helpp

#

its stuckes

deft wolf
#

Crazy support scam

alpine relic
#

yeah

#

help

alpine relic
# alpine relic

In Replit Its Running And All Not Error But In Hiating Its stuck In Loading

#

lol

#

he get banned

#

hoho

#

@deft wolf can u help

deft wolf
#

Idk lavalink and stuff like this so I don't think so

alpine relic
#

btw thx for William

alpine relic
glacial dew
#

Can someone recommend me best hosts for bots/websites?

deft wolf
#

Literally any VPS provider

jaunty mason
jaunty mason
#

(has more just wont post all of it to prevent flooding)

lyric mountain
jaunty mason
lyric mountain
#

also those are kinda saying the same thing

lyric mountain
jaunty mason
lyric mountain
jaunty mason
#

well i mainly did it cuz i thought it was fun 😭😭

jaunty mason
#

some are completely free but have extra add ons that aren’t core features

lyric mountain
jaunty mason
#

that are paid

jaunty mason
lyric mountain
jaunty mason
#

i’ll find a better way to display them

lyric mountain
#

it's a bit pedantic but inflated feature comparisons are a thing that always drive me off services

lyric mountain
#

as for the gambling stuff, u can call them minigames

jaunty mason
lyric mountain
#

as long as u dont advertise them as gambling it should be fine

#

ofc dont do actual gambling either

jaunty mason
#

😭😭

#

i thought it was harmless calling it gambling as it doesn’t involve real money

deft wolf
#

Then it's not really a gambling because it has no real value

lyric mountain
#

ye, just the usual discord minigame

jaunty mason
#

yea i guess u could view it that way

#

if u have any other comments js tell me

#

i’d be happy to update it

lyric mountain
#

nah the rest is fine

jaunty mason
#

alr bet

#

ty

hazy heron
eternal osprey
#

hey guys should i do feature hyperparameter tuning for 3 different models seperately?

#

I am trying to find the best params for n-grams, TF-IDF vectorization

#

but i use 3 different calssification models, so i am trying to understand whether i should just do it on 1 model and use those params for all, or do it on all models sepeately.

jaunty mason
#

@eternal osprey hyperparameters for vectorization depend on the model

#

so u should tune them seperately

#

TF-IDF and n-gram affect models in a different way

#

so sharing a config might not be optimal for the results ur hoping for

#

(i assume)

hazy heron
#

I'll brag a little too

#

made with skia-safe

jaunty mason
#

oh that looks good

#

i might need to take a little insperation

#

😭

#

hey quick question @hazy heron do u have any experience with doing some ethical hacking? i know theres some vulnerabilities in my web dashboard that could leak the token but i dont know where.

#

i think its in the enable slash commands tab.

hazy heron
#

I'm not really affected by that, because my dashboard is written in Rust
however I don't think it's possible to leak the bot's token that way

#

We have an api in the bot that we call every time there's a change in cmds

#

I'll look into it

jaunty mason
stoic bough
#

If your token is being handled server side it never reaches the browser

#

Unless you pass it into a request somewhere or response

hazy heron
#

if server doesn't send token to client there's no way to get it from the client

#

yeah, that

stoic bough
#

Well if you're using api

#

It should be in an authorization header

jaunty mason
#

well my main website makes requests to the api url and gets responses through there. the main bot is ran through the backend since the database is local so the bot passes it to the api

stoic bough
#

With something like 'Bearer BOT_TOKEN'

lyric mountain
#

the only token that should ever reach clientside is session token

hazy heron
#

you're using discord api directly?

stoic bough
#

And it should be hmac sha 256

#

By the time it reaches the player

hazy heron
#

I mean if it's by server actions it should be safe

jaunty mason
#

so

#

in the website

stoic bough
#

Your bot uses api routes

jaunty mason
#

someone logs in using oauth

stoic bough
#

To interact with your web dashboard

jaunty mason
stoic bough
#

?

#

Well I was gonna help you

#

But you're being snooty

#

Good luck

jaunty mason
#

is there another way to do it? its the only way i know how to do it