BGM (Block Generation Module)

Hello there developers!

NOTE: this is my first community resource so I’m probably going to make a lot of mistakes

INTRO

I came up with this idea yesterday and it’s basically a mine block generation system. It’s not as advanced as in it doesn’t go down forever, but it does the job! I just believe it’s going to save you a lot of hassle.

Source Code

local generation = {}

-- weighted randomization
local function choose_random_item(items)
	local total_weight = 0

	for _,item_data in pairs(items) do
		if item_data == "this is an ore table lol" then continue end
		total_weight = total_weight + item_data[2]
	end

	local chance = math.random(1,total_weight)
	local counter = 0
	for _,item_data in pairs(items) do
		if item_data == "this is an ore table lol" then continue end
		counter = counter + item_data[2]
		if chance <= counter then
			return item_data[1]
		end
	end
end

generation.new = function()
	local self = {}
	self.rarities = {
		signature = 'this is an ore table lol'
	}
	
	self.add_block = function(weight_table)
		------------------------------ Error handling ------------------------------
		if #weight_table ~= 2 then error("The weight table doesn't have the right amount of items! your faulty table: "..game:GetService("HttpService"):JSONEncode(weight_table)) end
		
		if not weight_table[1] then error("The first item is not found! your faulty table"..game:GetService("HttpService"):JSONEncode(weight_table)) end
		if not weight_table[1] then error("The first item is not found! your faulty table"..game:GetService("HttpService"):JSONEncode(weight_table)) end
		
		if typeof(weight_table[1]) ~= 'Instance' then error("The first item in the weight table isn't an Instance (it should be)! your faulty item: "..game:GetService("HttpService"):JSONEncode(weight_table[1])) end
		if typeof(weight_table[2]) ~= 'number' then error("The second item in the weight table isn't a number (it should be)! your faulty item: "..game:GetService("HttpService"):JSONEncode(weight_table)[2]) end
		------------------------------ Error handling ------------------------------
		
		table.insert(self.rarities, weight_table)
		
	end
	
	self.generate_blocks = function(starting_block, height, width, container)
		local temp_folder = Instance.new("Folder", workspace)
		temp_folder.Name = 'Container'
		local block_container = container or temp_folder
		if block_container ~= temp_folder then temp_folder:Destroy() end
		------------------------------ Error handling ------------------------------
		if not starting_block then error("Starting block not found!") end
		if starting_block:IsA("BasePart") == false and starting_block:IsA("Model") == false then error("Starting block isn't a BasePart nor a Model! "..starting_block.ClassName) end
		
		if starting_block:IsA("Model") then
			if not starting_block.PrimaryPart then error("Primary part not found in starting_block: ", starting_block) end
		end
		
		if not self.rarities then error("rarities table not found!") end
		if self.rarities == {signature = 'this is an ore table lol'} then error("rarities, table is empty, did you forget to add the rarities?") end
		local _, err = pcall(function() -- I don't know if this is the best way to check if a datatype is a table...
			table.freeze(self.rarities)
		end)
		if err then error('"rarities" is not a table! (should be)') end
		if not self.rarities.signature then error('Signature not found in "rarities" table!') end
		if self.rarities.signature ~= 'this is an ore table lol' then error("Signature not valid! (cmon man)") end
		
		if not typeof(height) == 'number' then error("Height is not a number, it's a "..tostring(typeof(height))..' 		...idiot') end
		if not typeof(width) == 'number' then error("Height is not a number, it's a "..tostring(typeof(height))..' 		...idiot') end
		------------------------------ Error handling ------------------------------
		local starting_block_position
		local starting_block_size
		
		if starting_block:IsA("Model") then
			starting_block_size = starting_block:GetExtentsSize()
			starting_block_position = starting_block:GetPrimaryPartCFrame().Position
		else
			starting_block_size = starting_block.Size
			starting_block_position = starting_block.Position
		end
		
		local starting_block_size_x = starting_block_size.X
		local starting_block_size_y = starting_block_size.Y
		local starting_block_size_z = starting_block_size.Z
		
		local posx = starting_block_position.X
		local posy = starting_block_position.Y
		local posz = starting_block_position.Z
		
		for height_integer = 1, height, 1 do
			posx = starting_block_position.X
			for width_integer_a = 1, width, 1 do
				posz = starting_block_position.Z
				for width_integer_b = 1, width, 1 do	
					posz += starting_block_size_z
					local blocc = choose_random_item(self.rarities):Clone()
					if blocc:IsA("Model") then
						blocc:SetPrimaryPartCFrame(CFrame.new(posx, posy, posz))
					else
						blocc.Position = Vector3.new(posx, posy, posz)
					end
					blocc.Parent = block_container
				end
				posx += starting_block_size_x
			end
			posy += starting_block_size_y
		end
		starting_block:Destroy()
	end
	return self
end

return generation

DOWNLOAD:
block_generation.lua (4.8 KB)

GET IT HERE:
Library

USAGE:

Constructor:


local module = require(path_to_module) -- requiring the module
local generation = module.new() -- constructing

Adding blocks:


generation.add_block({path_to_block, 1})

There's only one argument and that's a table with the first item being the block you want to add (can be a model or a basepart), and the other item is the rarity index (I'm using the weight technique so the lower the number the rarer it is)

Generate the cube:


generation.generate_blocks(path_to, 3, 3, path_to)

There's 3 arguments (and a 4th optional one). The first argument is the sample block. The code takes the sample block's size and position to generate the other blocks. The generation is going positively in all three axes, and the sample block is deleted after the generation is complete. The second argument is the height in blocks, and the third is the width in blocks. The fourth optional argument is the block container, i. e. the parent of the blocks. If not set the script will create a new one named "Block Container".

OUTRO

If there’s anything you’d like to say/add to it please don’t hesitate to leave a comment.

Showcase:
https://gyazo.com/9be410ef294ea4aa9c3a470bb937a1da

Bye bye!

4 Likes

Nice explanation about Block Generation Modules!

1 Like

any videos showcasing it? add em

1 Like