#development
1 messages · Page 308 of 1
hello there,
I made a Discord bot called TB Tea — it lets you chat across different servers 👀
I need testers if anyone interested pingme
No thanks
If I drop my bot website for public review here will it be promotion?
If you're honest and want a review of it as kind of feedback, other people have done it - so doubt
I just don’t wanna get muted for promoting
Others did so very likely doubt
I keep crashing studio
Screenshots were also sent so 🤷♂️
I think my terrain gen is too much 💀
@oak cliff maybe you can confirm
https://xlare.xyz ONLY FOR REVIEW
But it's also the dev channel so yeah, makes it even more suited for feedbacks and such
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 
Style-wise looks like every (AI related) website these days, don't know if it's a template or all LLMs giving the same style
Template

That's fair then
The rest is fine, haven't logged in, just maybe that when you switch pages you don't get scrolled back to the top
Oh would fix that
@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
gz
I use chunks and stuff too
btw, for the mountain stone u can base it off the difference between 2 coordinates in the noise map
Is that with marching cubes?
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
elseif rawHeight > amp * 0.4 then
mat = Enum.Material.Rock
end
here, store the previous x (or any horizontal coordinate) and rawHeight values and compare with current, if the angle between them is higher than 0.75 (for example) then u set mat as stone
local steepness = abs(rawHeight - prevHeight) / abs(x - prevX)
...
elseif steepness >= 0.75 then
mat = Enum.Material.Rock
end
Chunking is to reduce rendering stress & worldgen stress
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)
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
can also use the steepness for stuff like tree generation to prevent trees in impossible slopes
Also chunks make LODs easier to implement I think but not 100% sure
for terrain LOD yeah, since you dont need to compare every single vertex with current position
LOD?
level of detail
(Also makes GPU occlusion culling & frustum culling much easier)
I see
as in, nearer things are more detailed than the farther stuff
That way you only have to compare the AABBs of chunks instead of block-by-block
so you dont waste processing on things the viewer cant even notice
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
AS for this, I don't understand the math here for steepness
it's a basic slope angle formula
basically take two points in a 2d plane and check how "steep" the slope is between them
y2 - y1 / x2 - x1
goes from 0 (flat) to 1 (totally vertical)
I feel like I learned this in math class
sounds like the slope formula thing
it is
yeah I kinda flunked math and barely paid attention, now I regret it
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
lmao
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?
prevHeight would be the rawHeight of the previously visited coordinate
I need to set prevHeight after calulcating the steepness
not the current coordinate
also, you'll need to choose what to do on the first coord, since it'll not have either information
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 😭
note the rock walls on the mountains
now it's just a matter of finetuning
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

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

slow down buddy I just barely started understanding this, now we are talking about using masks
umm, lemme draw
😭
for example, imagine this is your current terrain noise
Yuh
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

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
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
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
you mean like adding + WATER_LEVEL to the biomeMap?
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
so local height = (rawHeight + baseHeight) + WATER_LEVEL ?
Hm okay
I think I did it correctly
Yeah okay
Resulting terrain
After tweaking the t and frequency of the rawHeight I got this
nearly there :D
the noise you're using for the water is too small, increase its size
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
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
I increased the size but the water didn't increase, only the amount of sand
are u adding a negative height offset to the water?
Terrain regen made a smiley face
lmaooo
anyways
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
gotta find why the smiley appeared lul
ah

What am I missing
I dont understand
-10 -> -5
but anything lower than -10 and I might as well released noahs ark
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
basically, the height offset for water should be smaller than 10 (so it doesnt cancel the seabed level)
u should lul

that's why I mentioned putting it into the biome class
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
ur a madlad
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
💀

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
You offset only rawHeight
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
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
isn't that what im doing here
Basically, the blackest area in land's noise map must be above sea
Yes, but u need to have different offsets for sea and for land

Nvm then, didn't notice
Instead of a hard cutoff
Usually we call it fac so I ignored it subconsciously
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
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
Not exactly sure how to get that specific
There is not water in it from what I can see
Water is only put in specific places
Yeah thats like a little pond in between the mountains
It's meant to be there based off the noise generated
But if that's a land biome, it shouldn't have water no?
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
Well, if it's intentional then it's fine
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 
Lul how did that even happen
I assume it's the cave portion of the code
Like, if the offset is right, the deepest valley in the land biome shouldn't ever go below water level
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

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

isn't local heightOffset = 0 + (WATER_LEVEL + 10) * t this what that does
yes, that's why I was confused as to why there's water there
wait, why are u doing t = t * t?
the value returned by biomeMap should be enough on its own
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
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
Can't believe you guys have been going at this for this long lol
Most dedicated helper oat award
waffle, come help too lul
but u know math >.>
A lil bit
we trying to figure out why there's water inside the mountains up there
latest
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
That’s what I was thinking
due to height offset, it'd not be possible to have the noise go below water
Yeah idk man I’m grasping at straws
Squaring t made flatter terrain more common
What does t represent
^
So yeah squaring it would make it smaller, anything x^2 < x for 0 < x < 1
that fac comes from a secondary biome map, smth like this ^
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
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
I don't really know what each variable represents atm so it's a bit difficult for me to read & catch up
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

Lmao aaron
I was about to tell you what each variable meant
👏
😭
send the paragraphs individually
LOOK Claude made the code it can explain its own hallucinations
and remove the emdashes
Oh oof
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
gotta leave too 
luke's turn
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
helpppp
I don't even understand this stuff and I'd say I have a decently strong math background
Yeah I guess I just don’t know how to apply it
Ima try and do more reading online
Rome wasn't built in a day
not yet™️
What in gods green earth is this
It’s just the mathematical definition of the noise function
It’s saying that given inputs x and y this is how you mathematically compute the value of fbm(x, y)
What's that weird E
That’s Sigma, it’s summation
also whats with n-1 and i=0 above and below it
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]
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
This looks pretty much exactly like what that mathematical function does with some slight modification
yeah it divides instead of multiplying
But yeah typically it’s useful to normalize between 0 and 1
Normalizing means that it’s a decimal point scaled between two values
Usually it’s either -1 and 1 or 0 and 1
Very common practice in ML, I think it’s pretty normal (no pun intended) in procgen too
Just more convenient to work with
Yeah it’s nice to know the range of values you can expect
Alright so I for the most part understand fBM
but not how to apply it
back to the virtual books
@lyric mountain right so figured out thats not what you meantlocal 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?
Well v1 is a bust
looks like no mans sky
Been working on a small project. An inspired discord bot game of Discord Scream 7 orb quest! 
iteration 4
increased the scale in rawHeight and upped the landHeight addition from 5 -> 10
This is very close to my desired outcome
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,
}
@lyric mountain hazaahhh
chunk spawning / despawning works
Still a bit laggy
Not sure how to really fix that 
The fps drops to like 1 for 20-30s on initial load
how often do mod checks tickets?
whenever they have time
its been a day and its a very critical issue
they have a life, they're volunteers
they have school, jobs, families, etc.
digital moderation obviously doesn't take precedence
That's why we should implement AI to handle tickets 
The response would be useless but at least it would be quick
cough discord cough

Maybe, maybe not
are u threading?
Yeah you need to spawn threads for this
Chunk generation and meshing is generally quite expensive
I do the best I can
I might be able to make it faster idk
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
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
I just have a thread pool and pass chunk generation tasks
then after processing you merge them back into a single result
that works too
I have a thread pool since I dynamically procgen chunks as the camera moves
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
The issue is the engine limitations
I am not sure if roblox allows actual multi-threading
which
it seems it does
Parallel Luau
Ooo interesting
This is what I am working on
Command previews for my commands
@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.
damn a 75% reduction
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
time for a documentation dive :D
only lua I ever used was starbound modding and programable mouse
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,
}
single thread can only do so much, eventually multi is a must
This is probably the most expensive part besides the actual generateChunk call
yeah but that wouldn't offer much performance benefits in the grand scheme of things
but I will do that for sure
and iirc lua uses dynamic typing, so try to be as unambiguous as possible
if u can use static types do use them
it did shave some time last time I was doing extreme optimization against tim
since it doesnt need to allocate space in loops
fair
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
the average time for the math is like ~70-80ms while the WriteVoxels call is like ~16ms avg
oh btw
I can do all the math in parallel luau and call WriteVoxels with the returned arrays outside of it
whenever possible, use integers
Keep in mind that you get 16.6ms of work per frame to maintain 60fps 😉
int math is much faster than floating math
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
u can do ittt
@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
Make sure that your actual game loop thread isn't doing the work. The game loop should just offload tasks to the other threads, so as to prevent visible fps stutter
Well here's the result
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
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
Yeah
one thing I am seeing
ecs is failing
Somehow my server ecs is not replicating what it needs to the client

Deduced the problem
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
lol
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
Woah
yeah sure
Gitea, Sourcehut or GitLab are nice
if you nas has less than 16gb of ram do not install gitlab 👍
mine has 16gb 🙂
gitea is nice tho
have it deployed on a smaller one with other services without issues
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
what do yall use the NAS for. Like what tools would be crucial for a nice homelab
yah
cuz next to gitea i am kinda stuck lmao
then you maybe don't need one ;)
too bad i already bought one
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
use it to run docker containers
buzzword detected

i actually wantto run my own infiscal instance
I mean thats the only usecase i'd have for it
run my dev docker containers
or like jellyfin
or something

but that means i need to use wireguard for it to connect to my server
that's hosted at datalix lmao
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 💀
adguard home 
i dont even use adguard to block anything
i just use it for caching and analytics
hmm
yeah i mean some ads are on the same domain so dns blocking won't be of much use
youtube is the perfect example
yeah i just use brave on all the pcs i manage
yeah pi-hole wont block youtube
i read some time ago that they're maybe pseudo working on making it proxy as well
which would solve those issues
they could embed it directly into the video stream
and intentionally slow the max dl rate down
so you literally cannot skip
no tech
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
never paid any so far ✌️
i accidentally found that i pushed a bunch of ds_store files to github..
are they sensitive in any sense?
no
they just expose path names
so just dont leak it online on a website as that can be used to find internal files
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
@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
Now make Minecraft
looks sick!

What are you making
How can we make it where when users vote it gives them a voter role
webhooks
Do u know how to set them up
https://docs.top.gg/docs/Resources/webhooks give you info on them, and you can find your library and it should have a section on it as well for that specific library
Webhook integration for receiving vote data
Thx
It's a procedural generated world game that lets players dictate the outcome of the world.
Awesome
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 
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.
Sounds awesome
Yeah
can't wait to see your progrss
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
Me either ahaha
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
What is your main project?
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
well mine isn't anything I don't know/someone couldn't do by just reading basic instructions
Looking good
Well this is no bueno
Player falls through the map, and I seriously can't figure out why it's spawning the player in so early

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
threads are async, are u awaiting for the initialization?
like, u dont (and shouldnt) need to wait for every chunk update, but u must wait for the very first terrain gen
the mask is always 32 bits long for ipv4
the prefix is a number from 0-32, usually deliminated with a /
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
Yeah, and I also only spawn the player until after all the writevoxel calls are done, but I think the issue is. The calls are done but that doesn’t mean Roblox has finished processing them
At this point im at a loss on what to do
I've added long delays, and they still fall through the terrain initially

I finally fixed it but I don’t think it’s the most elegant solution
use a mutex
like, have a variable that is only set to true after everything is done
local init = false -- on global context
...
thread work
...
init = true
gitea W
That’s what I do
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
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
Gimme another app to install on my nas
So far i got a local notion/trello dupe, mysql,gitea
🧠
Does anyone know why my bot’s profile picture is not appearing on its Top.gg page all of a sudden?
Funny enough despite having this issue for nearly a week it seemed to fix itself right when I asked about it
they use discord api for that
nope
they are working pretty well on compliance
huh damn
how strange
but first before they can fix this the tc39 community needs to have 6 months worth of discussion around it
how to remove status from bot?
1 biggus byte
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?
You can click "Copy URL" button to copy the url
Looks like it should be https://top.gg/api/v1/projects/@me
But looks like it doesn't contain any info about server count and votes variable is just a number
GET to fetch
POST to update
lemme try this
this worked it didnt show monthly votes nd points it seems did return server count
maybe api doesnt support those fields?
welp nothing showed and failed
this endpoint is only for server counts
if you’re talking about https://top.gg/api/bots/:bot_id/stats yes
i mean like the monthly votes etc
no way to get them right
i don’t think so anymore but you can map all the users who voted from your database it should match whats on topgg
your welcome
You can’t update votes
oh
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.
tailscale?
Just sign a certificate locally
And install it to your local cert store on the devices you connect to it with
Yeah I figured
Tailscale seems fun but i absolutely don’t want to expose the nas
To the internet
@lyric mountain So I stepped it up a bit and im using Unity now
Terrain is so much easier

thinking about using mkcert
@knotty night sorry mass ping im just showing where's its at
ooo
btw, if ur using jetbrains stuff, rider has official integration with unity
Most recent iteration
My plan is having large continents with vast oceans around them that people can sail too
Looking tundra
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
That to run in roblox?
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
💀
@lyric mountain We have water
Oooo it moves
Yeahh
It uses custom shaders that I admit claude made
cause I have 0 clue on shaders rn
hlsl?
Tbf, the semantics of something like hlsl is easy to grasp, but the math can get really complicated
Yeah
I’m not sure on how to do any of that so I just wanted something useable for now
Do you have the 1974 World Cup
I want minecraft
lynch him
Remember this so you can expose him on twitter once his game becomes popular
@sharp geyser be ready
i will blackmail u for that
hehehehehehehehe
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
TIL python bought an entire domain just for a function in their standard library 🙈
they don't want to make a seo progress
writing docs is so tiring 🙏 is this somewhat understandable https://calagopus.com/docs/panel/extensions/concepts/events
You try and write custom shaders knowing 0 clue on how 
i cant with the stupid shit cursor generates sometimes 😭
🤣
thanks cursor i knew you were looking out for me
half of that response doesnt make sense but yeah
the catch (_) is wild
considering you can just - not have it at all and do try { } catch { }
time to add try/catch everywhere
i think its relatively new in javascript terms so lots of code still uses a placeholder _
Don't forget to tell AI to do it
2019,
which is supported since nodejs 10.3
risky thing
who doesn't enjoy risky things
as the system grows, you can't catch the error message, and then you spend a lot of time debugging.
for those still using docker desktop on macos
or nodejs 6.7
no more 27.0 inches 🙏 only 27
not enough inches to fulfil your needs?

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.
When I think of “Tycoon” things I always think about the Nintendo DS “Animal Tycoon”
Yesss
I had to do a knockoff of “ghostface”
So it’s “masked killer”
H
Why not a reverse proxy with nginx?
I dont want to handle certs myself
Caddu automates it
Or just use cloudlares certs
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
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
boost is horrendous 😵💫 idk why people still use it
anyone know anything about recursive backtracking algorithm?
That’s a very general subset of algorithms
What about it specifically?
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
not sure if this is helpful or not
this requires me to give it a sample correct?
yeah I dont think WFC would work for me
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.
Yeah I just don’t think WFC will work for me since I have many constraints
Not to mention I’m using premade rooms
That wouldn’t necessarily work with WFC no?
Does anyone know any good hosts? My current one has unreliable uptime which caused my bot to be rejected unfortunately 💔
how are things around here nowadays
Hetzner, Contabo, OVH. Literally every major hosting provider is good but often expensive
OVH is actually the cheapest rn for the performance it offers
yippie
u can use DFS for that
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
sounds simple enough
what does one do after creating a bot with 700 commands
realise only ~50 are used and rewrite the entire thing
Delete it and start over by creating something useful instead of a kitchen sink bot
realise they wasted their time and move on
no literally
it has 752 commands
potentially
i made it pure out of anger because dyno doesnt have the most basic things and i dont feel like adding 100 bots to my server
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
i doubt it. the most u could merge it into is probably 300 if u really cramped it
yes
My god
literally has over 70 folders
😭
i tried organizing them but uh
i put each command category in its own folder
meaning
it has like 50 categories now
sussy redaction
huh?
whats redaction
sorry english isnt my first language
😭
the hidden category
--> ||redacted||
thanks for explaining
epstein files trailer
except they failed
People invite dozens of bots to avoid hundreds of commands. Thats way too many good lort
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 😭
Bottom = default.. O.o
How much time?
a lot
@delicate zephyr
Good automod rules 👍
Crazy support scam
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
Idk lavalink and stuff like this so I don't think so
btw thx for William
its can running smooth on replit but not in hosting
Can someone recommend me best hosts for bots/websites?
Hidencloud
Literally any VPS provider
schizophrenia at its finest
according to my research it wasnt a waste of time
(has more just wont post all of it to prevent flooding)
stating "gambling games" will prevent u from ever being approved for bot discovery
what? doesn’t owo have that and it gets used everywhere?
also those are kinda saying the same thing
maybe, but they likely used some loophole to get in
true but some do have premium paywalls
oh?
ye, but "completely free" already cover the other 2
well i mainly did it cuz i thought it was fun 😭😭
ehh
some are completely free but have extra add ons that aren’t core features
u can still have it, just need to figure a way to make them not look like gambling
that are paid
so rename them and make them look more like actual games rather than a casino?
then they're free, not completely
idk i view it a different way but thanks for pointing it out
i’ll find a better way to display them
it's a bit pedantic but inflated feature comparisons are a thing that always drive me off services
understandable
as for the gambling stuff, u can call them minigames
yeah i was thinking that
as long as u dont advertise them as gambling it should be fine
ofc dont do actual gambling either
no no ofc not
😭😭
i thought it was harmless calling it gambling as it doesn’t involve real money
Then it's not really a gambling because it has no real value
ye, just the usual discord minigame
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
nah the rest is fine
amazing work
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.
thanks
@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)
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.
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
i do that too but couldnt they use the browser console to bypass that?
how so
If your token is being handled server side it never reaches the browser
Unless you pass it into a request somewhere or response
if server doesn't send token to client there's no way to get it from the client
yeah, that
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
With something like 'Bearer BOT_TOKEN'
the only token that should ever reach clientside is session token
I mean if it's by server actions it should be safe
Your bot uses api routes
someone logs in using oauth
To interact with your web dashboard
obviously
is there another way to do it? its the only way i know how to do it



