Which functions should I add to my ModuleScript?

Not sure if it would fit every scripter but I’d definitely find a utility which hooks into ChatService and allows you to send messages to players without having to deal with channels and speakers useful :slight_smile:

Finished on the leaderstat creator, you can now make leaderstats with ease!
image

2 Likes
function module:GetModelMass(model)
   local Mass = 0
   
   for _,descendant in pairs(model:GetDescendants()) do
      if (descendant:IsA("BasePart")) then
         Mass = Mass + descendant:GetMass()
      end
   end

   return Mass
end
1 Like

Interesting, good to know.
Thank you.

Not a function, but separate your utilities by type/task/so on so developers can salvage and use parts independent of the grand ModuleScript. Cluttering all kinds of functions into a single ModuleScript can and will get annoying not only for you as a maintainer but a developer as a user of this as well.

2 Likes

Cool! Hopefully it will prove useful! Also, do you have a estimated time for when the module will be finished?

Something I have in my module that I’m sure will be useful:

A function that returns the server type; normal, vip or reserved. If it’s a vip server potentially also the server owner. If I had access to my laptop right now I’d provide my code but it’s a bit late.

1 Like

Extra table functions. Such as contains and count (for tables that contain strings for keys)

It may be a bit better because the second argument of Instance.new is not recommended to use (according to a DevForum article). Upon reading this article, I completely ended my habit of using the second argument. It would be a very simple function to run. (The article is from around two and a half years old, so I may be incorrect.)

A function I use a lot is this table randomizer, takes a table as input and returns the same table but the contents inside of it randomized.

function RandomizeTable(tbl)
local newt = {}
for i = 1, #tbl do
local n = math.random(1, #tbl)
table.insert(newt, tbl[n])
table.remove(tbl, n)
end
return newt
end

It’s great that you’re doing this! I don’t know if your module already has the following functions, but one that I know is used a lot is to shorten a number by using SI prefix symbols along with one that keeps a set number of decimals.

Here are some other simple functions that I have in my own module:

  • Convert dictionary to array
  • Return the object with the specified value at the designated key in an array of objects (dictionaries)

Basicly math functions but for vectors.
So math.vectorClamp(v,minv,maxv); math.vectorEquals(v0,v1); math.vectorLowerThan(v0,v1); math.vectorLowerEquals(v0,v1) you get the point. Functions like these would be amazing to have and it’s a real bummer that we don’t have them by default. A must have in the module in my opinion!

If you want to get so far with it I will suggest you to make a part:GetPartsWelded() that will return all the parts that are relying on that part for welds.

1 Like

Hmm. I’m not sure I would use this myself, but I guess some people might. I have my own ModuleScript full of random functions that I use across many of my projects, but what’s the point of putting stuff like math.random or other “standard library” functions? It’s already available without having to require another module.

Anyway, I’ll post my own utility function module, feel free to use any of them if you think they might be useful.

my 'utility function' module
local TagS = game:GetService("CollectionService")
local random = Random.new(os.time())

--Various utility functions that might be used across several scripts
local util = {}

function util.map(v, a0, a1, b0, b1)
	--Maps number v from range [a0-a1] to range [b0-b1]
	local aNormalized = (v-a0)/(a1-a0)
	return b0 + (b1-b0) * aNormalized
end

function util.filter(t, filter, ...)
	--Returns elements of t that satisfy the condition filter(t)
	local result = {}
	
	for _, v in pairs(t) do
		if filter(t, ...) then
			table.insert(result, v)
		end
	end
	
	return result
end

function util.combine(t0, ...)
	--Concatenates any number of tables
	local ts = {...}
	for _, t in pairs(ts) do
		for _, v in pairs(t) do
			if not util.indexOf(t0, v) then
				table.insert(t0, v)
			end
		end
	end
	return t0
end

function util.indexOf(t, value)
	--Returns the index at which value is found in the table t, or nil if it is not found
	for i, v in pairs(t) do
		if v == value then
			return i
		end
	end
	
	return nil
end

function util.getChildrenOfClass(parent, class)
	--Gets a list of children of parent, which have the ClassName class
	local ch = {}
	
	for _, v in pairs(parent:GetChildren()) do
		if v.ClassName == class then
			table.insert(ch, v)
		end
	end
	
	return ch
end

function util.turnFaceToFront(cframe, face)
	--Returns a rotated CFrame so that its' given face faces towards its' previous lookVector/ front face
	
	local angles
	if face == Enum.NormalId.Front then
		angles = CFrame.Angles(0, 0, 0)
	elseif face == Enum.NormalId.Back then
		angles = CFrame.Angles(math.pi, 0, 0)
	elseif face == Enum.NormalId.Left then
		angles = CFrame.Angles(0, -math.pi/2, 0)
	elseif face == Enum.NormalId.Right then
		angles = CFrame.Angles(0, math.pi/2, 0)
	elseif face == Enum.NormalId.Top then
		angles = CFrame.Angles(-math.pi/2, 0, 0)
	elseif face == Enum.NormalId.Bottom then
		angles = CFrame.Angles(math.pi/2, 0, 0)
	end
	
	return cframe * angles
end

function util.majorAxis(v3, abs)
	--Returns the name of the largest component of a Vector3
	--If abs is true-like, the component with the largest absolute size is considered instead
	
	local abs = math.abs
	local x, y, z
	
	if abs then
		x, y, z = abs(v3.X), abs(v3.Y), abs(v3.Z)
	else
		x, y, z = v3.X, v3.Y, v3.Z		
	end
		
	local max = math.max(x, y, z)
	
	if x == max then
		return 'X'
	elseif y == max then
		return 'Y'
	else
		return 'Z'
	end
end

function util.otherAxes(axis)
	--Given the name of an axis, returns the names of the other two axes
	
	if axis == 'X' then
		return 'Y', 'Z'
	elseif axis == 'Y' then
		return 'X', 'Z'
	elseif axis == 'Z' then
		return 'X', 'Y'
	else
		error()
	end
end

function util.round(n, to)
	--Rounds a number to the nearest 'to', e.g. nearest 0.5 or nearest 10
	
	if to == 0 then return n end
	return math.floor(n/(to or 1) + 0.5) * (to or 1)
end

local round = util.round

function util.roundVector3(v3, to)
	--Returns a Vector3, with each component rounded to the nearest 'to'
	
	return Vector3.new(
		round(v3.X, to),
		round(v3.Y, to),
		round(v3.Z, to)
	)
end

function util.roundVector3V3(v3, to)
	--Returns a Vector3, with each component rounded with respect to each component of the Vector3 'to'
	
	return Vector3.new(
		round(v3.X, to.X),
		round(v3.Y, to.Y),
		round(v3.Z, to.Z)
	)
end

function util.v3FromAxes(axis1Name, axis1Value, axis2Name, axis2Value, axis3Name, axis3Value)
	--Creates a Vector3 from three sets of axis names and axis values
	--This makes it possible to create a Vector3 without knowing the order of the axes
	
	local t = {}
	
	if axis1Name == 'X' then
		t.X = axis1Value
	end
	if axis2Name == 'X' then
		t.X = axis2Value
	end
	if axis3Name == 'X' then
		t.X = axis3Value
	end
	if axis1Name == 'Y' then
		t.Y = axis1Value
	end
	if axis2Name == 'Y' then
		t.Y = axis2Value
	end
	if axis3Name == 'Y' then
		t.Y = axis3Value
	end
	if axis1Name == 'Z' then
		t.Z = axis1Value
	end
	if axis2Name == 'Z' then
		t.Z = axis2Value
	end
	if axis3Name == 'Z' then
		t.Z = axis3Value
	end
	return Vector3.new(t.X, t.Y, t.Z)
end

function util.v3InSphere(r)
	--A random Vector3 with magnitude <= r
	local v3
	repeat
		v3 = Vector3.new(
			random:NextNumber(-1, 1),
			random:NextNumber(-1, 1),
			random:NextNumber(-1, 1)
		)
	until v3.Magnitude < 1
	
	return v3 * r
end

function util.v3OnSphere(r)
	--A random Vector3 with magnitude = r
	return util.v3InSphere(1).Unit * r
end

function util.faceToNormal(part, face)
	--Returns the direction that a face on a part is pointing
	
	return part.CFrame:vectorToWorldSpace(Vector3.FromNormalId(face))
end

function util.nextFace(face)
	--Given a face, returns the next face Enum
	
	local faces = Enum.NormalId:GetEnumItems()
	local index = util.indexOf(faces, face) + 1
	if index > #faces then
		index = 1
	end
	return faces[index]
end

function util.normalToFace(part, normal)
	--Returns the face on a part that is closest to pointing in the direction of 'normal'
	
	local bestFace, smallestError = nil, math.huge
	local objectNormal = part.CFrame:vectorToObjectSpace(normal)
	
	for _, face in pairs(Enum.NormalId:GetEnumItems()) do
		local faceNormal = Vector3.FromNormalId(face)
		local faceError = (-objectNormal:Dot(faceNormal) + 1) * 0.5
		
		if faceError == 0 then
			smallestError = 0
			bestFace = face
			break
		end
		
		if faceError < smallestError then
			smallestError = faceError
			bestFace = face
		end
	end
	
	return bestFace, smallestError
end

function util.faceToAxis(face)
	if face == Enum.NormalId.Front or face == Enum.NormalId.Back then
		return Enum.Axis.Z
	elseif face == Enum.NormalId.Left or face == Enum.NormalId.Right then
		return Enum.Axis.X
	elseif face == Enum.NormalId.Top or face == Enum.NormalId.Bottom then
		return Enum.Axis.Y
	else
		error()
	end
end

function util.findTaggedChild(instance, tag, recursive)
	return util.findTaggedChildren(instance, tag, recursive)[1]
end

function util.findTaggedChildren(instance, tag, recursive)
	local c = {}
	local list = (recursive and instance:GetDescendants()) or instance:GetChildren()
	for _, v in pairs( list ) do
		if TagS:HasTag(v, tag) then
			table.insert(c, v)
		end
	end
	return c
end

function util.findTaggedAncestor(descendant, tag)
	for _, tagged in pairs(TagS:GetTagged(tag)) do
		if descendant:IsDescendantOf(tagged) then
			return tagged
		end
	end
end

function util.weldBetween(a, b)
	--Make a new Weld and Parent it to a.
	local weld = Instance.new("Weld", a)
	--Get the CFrame of b relative to a.
	weld.C0 = a.CFrame:inverse() * b.CFrame
	--Set the Part0 and Part1 properties respectively
	weld.Part0 = a
	weld.Part1 = b
	--Return the reference to the weld so that you can change it later.
	return weld
end

function util.rayCast(ray, whitelist)
	return game.Workspace:FindPartOnRayWithWhitelist(ray, whitelist)
end

return util

EDIT: Oh, and here’s a fractal noise generator I use for all sorts of procedural generation:

fractal noise
local r = Random.new(os.time())

function fractalNoiseGenerator(seed, amplitude, frequency, octaves, lacunarity, persistence)
	--Generates a fractal noise generator using cohrent noise (math.noise)
	--Uses "sensible" default values. 
	--Check out this glossary: http://libnoise.sourceforge.net/glossary/index.html
	
	local noise = math.noise
	local seed = seed or (r:NextInteger(-10e3, 10e3) * math.pi) -- * pi because noise is weird at integer coordinates, and pi is irrational
	local amplitude = amplitude or 1
	local frequency = frequency or 4
	local period = 1/frequency
	local octaves = octaves or 5
	local lacunarity = lacunarity or 1.75
	local persistence = persistence or 0.8
	
	return function(x, y, z)
		local v = 0
		local a = amplitude
		local f = frequency
		
		for o = 1, octaves do
			v = v + noise(seed + x*f, seed + y*f, seed + z*f) * a
			a = a * persistence
			f = f * lacunarity	
		end
		
		return v
	end
end

return fractalNoiseGenerator

Thanks for the advice!
I’ll be sure to do what you recommend!

1 Like

Script Benchmarker.

Put a tick at the beginning and end of the function/loop of any script you want to benchmark and pass them as arguments to the function, returns an average time a bit of code takes to execute. Useful if you have performance problems and are testing performance solutions in your script!

local results = {}
local count = 0
local total = 0
local benchmarking = false

function measureTick(tick2, tick1)
	if #results <= 1000 then -- Sample Count, increase for higher accuracy but takes longer to finish.
	local result = tick1 - tick2
	table.insert(results, #results + 1, result)
        --print("SAMPLES TAKEN: "..#results..) -- Optional, will show progress but completely fill up your output
		if #results >= 1000 and benchmarking == true then
			print("Generating Results")
				for i = 1, #results do
				total = total + results[i]
				if i >= 1000 then
					total = total / #results
					print("RESULTS ARE: "..total)
				end
			end
		end
	end
end

Haha cool. Roblox jQuery. Call it roQuery lol

Sorry getting back to you so late, the ModuleScript is nearing release.
Should be released this week perhaps.

2 Likes

Yay! I’m excited! And don’t fell bad, people are busy now a days! :smiley:

A cutscene creator, create cutscenes with ease and being able to change their easing style, easing direction, delay, reverse, duration, and also setting parts as focus points and or camera points. Then having it play it back.

2 Likes