A module of functions that I use alot

So I made this module a couple of days ago, and it was very useful to me.
I don’t know if this is optimized, since I made it.
But I use it alot so I thought I could share it here, you may copy it if use want, I’ll also post a quick guide on how to use the functions.

module:

local Global = {}
local TS = game:GetService("TweenService")

Global.__schedules = {}
Global.__checkers = {}
Global.__MultiAnimations = {}

function Global.After(exe : (...any) -> ...any, aexe : (...any) -> ...any, pause : number, exeArgs : {any}, aexeArgs : {any}) : (boolean, any)
	local result, errormsg = pcall(function()
		local res1 = exe(table.unpack(exeArgs))
		task.wait(pause)
		local res2 = aexe(table.unpack(aexeArgs))
		
		return res1, res2
	end)
	
	return result, errormsg
end

function Global.CreateMultiAnimation(animName : string,property : string, defaultInfo : TweenInfo, ...)
	local anim = {}
	anim["Property"] = property
	
	local tweenInfos = {}
	for i,v in pairs(table.pack(...)) do--round one
		if typeof(v) ~= "TweenInfo" then continue end
		table.insert(tweenInfos, v)
	end
	
	local curIndex = 1
	for i,v in pairs(table.pack(...)) do-- round two
		if typeof(v) == "TweenInfo" then continue end
		local keyframe = {}
		keyframe["Info"] = tweenInfos[curIndex] or defaultInfo
		keyframe["Value"] = v
		table.insert(anim, keyframe)
		
		curIndex += 1
	end
	
	Global.__MultiAnimations[animName] = anim
end

function Global.RunMultiAnimation(animName : string, obj : Instance, repeats : number, reverse : boolean)
	local anim = Global.__MultiAnimations[animName]
	if not anim then return false end
	
	for i = 0, repeats or 1 do
		for i, v in pairs(anim) do
			if i == "Property" then continue end
			if obj[anim["Property"]] and (typeof(obj[anim["Property"]]) ~= typeof(v["Value"])) then continue end

			local tweenSettings = {}
			tweenSettings[anim["Property"]] = v["Value"]

			local tween = TS:Create(obj, v["Info"], tweenSettings)

			tween:Play()
			tween.Completed:Wait()
		end
		
		if not reverse then continue end
		local property = anim["Property"]
		local reversearr = Global.ReverseArr(table.clone(anim))
			
		for i,v in pairs(reversearr) do
			if obj[anim["Property"]] and (typeof(obj[anim["Property"]]) ~= typeof(v["Value"])) then continue end

			local tweenSettings = {}
			tweenSettings[anim["Property"]] = v["Value"]

			local tween = TS:Create(obj, v["Info"], tweenSettings)
			tween:Play()
			tween.Completed:Wait()
		end
	end
end

function Global.ReverseArr(arr) : {any}
	local i, j = 1, #arr

	while i < j do
		arr[i], arr[j] = arr[j], arr[i]
		i = i + 1
		j = j - 1
	end

	return arr
end


function Global.CreateChecker(checkerName : string)
	local checker = {}
	Global.__checkers[checkerName] = checker
end

function Global.AddCase(checkerName : string, value : any, exe : (...any) -> ...any, ...)
	local checker = Global.__checkers[checkerName]
    if not checker then return false end

	checker[value] = {Function = exe, Arguments = table.pack(...)}
	return true
end

function Global.Check(checkerName : string, obj : any, removeAfter : boolean)
	local checker = Global.__checkers[checkerName]
	if not checker then return false end
	
	local result = nil
	local hasRan = false
	for i,v in pairs(checker) do
		if i ~= obj then continue end
		result = v["Function"](table.unpack(v["Arguments"]))
		hasRan = true
		break
	end
	
	if removeAfter then Global.__checkers[checkerName] = nil end
	if not hasRan then
		if not checker["default"] then return false, nil end
		
		result = checker["default"]["Function"](table.unpack(checker["default"]["Arguments"]))
		return true, result
		
	else return true, result
	end
end

function Global.Uncheck(checkerName : string)
	if not Global.__checkers[checkerName] then return end
	Global.__checkers[checkerName] = nil
end

function Global.RemoveSchedule(scheduleName : string)
	if not Global.__schedules[scheduleName] then return end
	Global.__schedules[scheduleName] = nil
end

function Global.CreateSchedule(scheduleName : string)
	local schedule = {}
	Global.__schedules[scheduleName] = schedule
end

function Global.AddFunc(scheduleName : string, exe : (...any) -> ...any, pause : number, ...)
	local schedule = Global.__schedules[scheduleName]
	if not schedule then return false end
	
	local funcdesc = {Function = exe, Arguments = table.pack(...), Pause = pause}
	table.insert(schedule, funcdesc)
	
	return true
end

function Global.AddFuncs(scheduleName : string, ...)
	local schedule = Global.__schedules[scheduleName]
	if not schedule then return false end
	
	local funcArgs = {}
	local args = {}
	
	for i,v in pairs(table.pack(...)) do--Pass one
		if typeof(v) == "function" then
			if i == 1 then continue end
			
			table.insert(funcArgs, table.clone(args))
			table.clear(args)
			continue
		end
		
		table.insert(args, v)
	end
	table.insert(funcArgs, args)
	
	local curIndex = 1
	for i,v in pairs(table.pack(...)) do--Pass two
		if typeof(v) ~= "function" then continue end
		local ourArgs = funcArgs[curIndex]
		
		local possiblePause = ourArgs[1]
		if typeof(possiblePause) == "number" then
			table.remove(ourArgs, 1)--remove to use this num as wait time.
		else
			possiblePause = 1--set default value
		end
		
		local funcDesc = {Function = v, Arguments = ourArgs, Pause = possiblePause}
		table.insert(schedule, funcDesc)
		curIndex += 1
	end
	
	return true
end

function Global.TO(condition : boolean, obj1, obj2)--TO: Terinary Operator
	if condition then return obj1 end
	return obj2
end

function Global.Run(scheduleName : string, removeAfter : boolean) : {any}
	local schedule = Global.__schedules[scheduleName]
	if not schedule then return false end
	
	local results = {}
	for i,v in pairs(schedule) do
		local resuls, errormsg = pcall(function()
			return v["Function"](table.unpack(v["Arguments"]))
		end)
		
		task.wait(v["Pause"])
		
		if not resuls then print(errormsg) continue end
		table.insert(results, errormsg)
	end
	
	if removeAfter then
		Global.__schedules[scheduleName] = nil
	end
	
	return results
end

return Global

so this is a handful I know but I’ll go over it okay.
so the first few lines are storage tables and the module itself.
Just ignore, they aren’t part of the module’s exposed members. (as indicated by the double underscore naming convention)

the first function is called After it needs two functions exe and aexe, followed by a parameter which indicates how much time to wait between the two calls, then two arrays containing the arguments for both functions,

it runs both functions one after the other with the specified time in between, and returns the result, it also logs any errors that occurred during execution.

the next one is CreateMultiAnimation which needs a name for the animation (for later access), the property that needs to be modified , a default tweeninfo when there aren’t enough tweeninfos. and then a collection of tweeninfos and values.
the tweeninfos are going to be combined with the value to create a keyframe, which then will be added to the animation and saved to __MultiAnimations.

then its close relative RunMultiAnimation will go over each keyframe and animate it with tweenservice, this way you can create animations that consist of multiple goal values.

example usage:

local GlobalFuncs = require(your location) -- placeholder

GlobalFuncs.CreateMultiAnimation("CoolAnim", "Color", uiMovementInfo, 
	Color3.fromRGB(255, 0, 0), --this works since it implicitly uses the default value
	Color3.fromRGB(255, 170, 0),-- but you can pass a tweeninfo if you want...
	Color3.fromRGB(255, 255, 127),
	Color3.fromRGB(85, 255, 127),
	Color3.fromRGB(0, 170, 255),
	Color3.fromRGB(0, 85, 255),
	Color3.fromRGB(170, 0, 255)
)
GlobalFuncs.RunMultiAnimation("CoolAnim", workspace.Part, 15, true)--run it 15 times in reverse to 
--get a cool rainbow animation!

here is a video of me looking at the animation:

so the next function in the module is reverseArr, a much needed one.
This should be in the std of lua, I don’t know why this doesn’t exist, but it reverses the order of an array (not a dictionary, they don’t have an order)

next up is CreateChecker, now I called it checker because it basically checks for equality, but you might know it from other languages under the name: The Switch Statement.
this function creates a switch statement with the given name (for later access).

then you can add cases to it using AddCase which needs the name of the checker, the value to check and any function to run, after that you can specify any arguments but that isn’t required for most statements.

then you can call Check with an object, and it will run the function under the case that matches the object.
if none match it checks for a default case, and quits if there are none.
But if there is a default case, which you can add by saying: AddCase("Your Checker", "default", your func, your args)
it will run the default case instead.
example usage:

local Global = require(PlaceholderLocation)--replace with module loc.

Global.CreateChecker("test")
Global.AddCase("test", 1, print, "it is 1")
Global.AddCase("test", 2, print, "it is 2")
Global.AddCase("test", 3, print, "3rd time is the charm")
Global.AddCase("test", "default", print, "no matches? *mega mind meme*")

Global.Check("test", 2, false)--will print it is 1
Global.Check("test", 8, false)-- will print no matches? *mega mind meme*
Global.Check("test", 3, true)-- will print 3rd time is the charm
Global.Check("test", 5, true)--will error because the checker got removed in the last call
--because args are Check(name, value, remove?)

Then there’s Uncheck which is the evil twin brother, because it removes a check statement from the storage.
it requires the name of the checker

There is RemoveSchedule which removes a schedule from the storage.
It needs the name of the schedule.

there is CreateSchedule which creates a schedule, a schedule is a list of functions which will be called from top to bottom with the given wait time in between and the given arguments, (so basically After but better)

you can add one function using AddFunc which needs the schedule name, the function, wait time before calling the next function, and a collection of arguments.
it adds one function to the schedule.

Then there’s AddFuncs which adds a range of different functions to the schedule, all with their own wait time and arguments, in a specific order.
the order is: function, (optional) waittime, (optional) args, next function, etc…
if no wait time is given it will default to 1

then you can run the schedule using Run which will call each function in order, with the wait time from addfunc or addfuncs in between.

example usage:

local mod = require(module location)

mod.CreateSchedule("test")
mod.AddFuncs(
  print,--no wait time given, so it uses 1
 "Hello",
  print,
  5,--wait time given, it uses 5
  "hi",
  print,
  5,-- wait time given, it uses 5
  10,--this will not be used as wait time, because 5 got chosen, 
--so this will be passed to print
  "hello",
  "hey",
  print,--defaults to 1
  "done"
)
--you can then run your schedule as many times as you want,
mod.Run("test", false)
mod.Run("test", false)
mod.Run("test", true)--until you remove it, then it dies.

and then the very last function is TO, which stands for Ternary Operator, you know… the:
Type name = condition ? object1 : object2;
from other languages.
it needs a condition, and two object,s and it will pick one based on the condition.

That’s all I guess…
I’ve never posted a resource before, feel free to give criticism and your opinions.

Bye!

3 Likes

Not a bad module, but some stuff can be better. For example accepting table entries instead of ..., and better typing, changing this would make it (imo) way waaay better.

2 Likes

you can use this for a ternary operator in roblox.

local result = condition and object1 or object2

A bit late, but I don’t like the Checker. It should be used with an Object Oriented Programming approach using classes:

local checker = Checker.new()

checker:AddCase(1, function() print("It is 1") end)
checker:AddCase(2, print, "It is 2")
checker:Default(print, "Default case")

for i = 1, 5 do
   checker:Check(i)
end

This way, you don’t have to label your checker and it doesn’t uses any global state.