[FIXED] [Open Source] Gear Utility

Gear Utility

UPDATE:

This plugin has been fixed. I have added checks to ignore Roblox tablets; otherwise, your account could be terminated for “fake login screens”.

Features:

  • Gear Importer
  • Gear Fixer

This plugin is designed to import most gears from the ROBLOX Catalog and fix them. Since ROBLOX removed the LoadLibrary feature, most gears are now broken. However, this plugin will automatically fix them for you.

To use this plugin, simply install it, open your place, and click on “Load Gears.” The gears will then be loaded with the necessary fixes applied. Alternatively, if you already have a gear, you can select it and click on “Fix Object.” You can also select folders, and the plugin will fix everything inside the folder.

I’ve spent a considerable amount of time coding a Python script to grab the gears and create an auto-fixer, so crediting would be greatly appreciated! <3

Visit the Gear Utility plugin on ROBLOX

[Demo video on YouTube]
(Gear Utility Demo - YouTube)

Here’s the source code:

local ChangeHistoryService = game:GetService("ChangeHistoryService")
local Selection = game:GetService("Selection")
local HttpService = game:GetService("HttpService")
local ServerStorage = game:GetService("ServerStorage")
local InsertService = game:GetService("InsertService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local JointsService = game:GetService("JointsService")

local Toolbar = plugin:CreateToolbar("Gears Utility")

local LoadGearsButton = Toolbar:CreateButton("Load Gears", "Load gears on Roblox", "rbxassetid://5711524831")
local FixObjectButton = Toolbar:CreateButton("Fix Object", "Fix object and its childrens", "rbxassetid://6172144323")
local UpdateModulePackagesButton =
	Toolbar:CreateButton("Update Packages", "Update gear module packages", "rbxassetid://6022668955")

local ModuleStart = 'game:GetService("ReplicatedStorage"):WaitForChild("GearModulesFolder"):WaitForChild("'
local ModuleEnd = '")'

local LoadLibraryFunction = "local function LoadLibrary(Library)"

local TreeTab = "					"

local function GetModule(Module)
	return ModuleStart .. Module .. ModuleEnd
end

local LoadLibraryRequire = "require(" .. GetModule("LoadLibrary") .. ")(Library)"

local ReplaceList = {
	[754568173] = GetModule("SwordModule"), --Sword Module
	[172349822] = GetModule("GearModule"), --Gear Module
	[191816425] = GetModule("MultiPurposeModule"), --Multi Purpose Module
	[201433042] = GetModule("ScaleCharacterModule"), --Scale Character Module
	[1075123174] = GetModule("GearService"), --GearService
	[199238756] = GetModule("SkateboardModule"), --Skateboard Module
	[836581200] = GetModule("PackageMaker"), --Package Maker
	[180464321] = GetModule("HalloweenMonsterCustomesLibrary"), --Halloween Monster Costumes Library
	[185791213] = GetModule("GuitarModule"), --Guitar Module
	["NPCModule = require%(game%.ServerScriptService%.MainModule%)"] = "NPCModule = require(" .. GetModule(
		"MultiPurposeModule"
	) .. ")",
}

function IsCodeHolder(Object)
	return Object:IsA("Script") or Object:IsA("LocalScript") or Object:IsA("ModuleScript")
end

function CreateTestScript()
	local Success, Error = pcall(function()
		local NewScript = Instance.new("Script")

		NewScript.Name = "GearUtility_TestScript"
		NewScript.Parent = JointsService
	end)

	return Success
end

function EditTestScript(Script)
	return pcall(function()
		Script.Source = 'print("Works!")'
	end)
end

function CheckCodeHolderPermission()
	local Success = CreateTestScript()

	if not Success then
		print("Please allow plugin access to create scripts")

		repeat
			task.wait(1)
		until CreateTestScript() == true
	end

	Success = EditTestScript(JointsService:WaitForChild("GearUtility_TestScript"))

	if not Success then
		print("Please allow plugin access to edit scripts")

		repeat
			task.wait(1)
		until EditTestScript(JointsService:WaitForChild("GearUtility_TestScript")) == true
	end

	for Index, Object in pairs(JointsService:GetChildren()) do
		if Object:IsA("Script") and Object.Name == "GearUtility_TestScript" then
			Object:Destroy()
		end
	end
end

function FixCodeHolder(CodeHolder)
	CheckCodeHolderPermission()

	local NeedModules = false
	local CodeHodlerFixed = false

	if CodeHolder.Source:find("LoadLibrary") then
		NeedModules = true

		if not CodeHolder.Source:find(LoadLibraryFunction, 1, true) then
			local LoadLibraryCode = LoadLibraryFunction .. "\n"
			LoadLibraryCode ..= "	return " .. LoadLibraryRequire .. "\n"
			LoadLibraryCode ..= "end"

			CodeHolder.Source = LoadLibraryCode .. "\n\n" .. CodeHolder.Source

			CodeHodlerFixed = true
		end
	end

	for Key, Value in pairs(ReplaceList) do
		if CodeHolder.Source:find(Key) then
			NeedModules = true

			CodeHolder.Source = CodeHolder.Source:gsub(Key, Value)

			CodeHodlerFixed = true
		end
	end

	if CodeHolder.Name == "BackpackMonitor" and not CodeHolder.Disabled then
		CodeHolder.Disabled = true

		CodeHodlerFixed = true
	end

	return NeedModules, CodeHodlerFixed, CodeHolder.ClassName
end

function Fix(Object)
	CheckCodeHolderPermission()

	local FixedCodeHolder = {
		Script = 0,
		LocalScript = 0,
		ModuleScript = 0,
	}

	print("Fixing " .. Object:GetFullName())

	local Time = os.time()

	local TotalFixed = 0
	local CreateModule = false

	if IsCodeHolder(Object) then
		local NeedModules, CodeHodlerFixed, CodeHolderType = FixCodeHolder(Object)

		if NeedModules then
			CreateModule = true
		end

		if CodeHodlerFixed then
			FixedCodeHolder[CodeHolderType] += 1
			TotalFixed += 1
		end
	end

	for Index, Object in pairs(Object:GetDescendants()) do
		if IsCodeHolder(Object) then
			local NeedModules, CodeHodlerFixed, CodeHolderType = FixCodeHolder(Object)

			if NeedModules then
				CreateModule = true
			end

			if CodeHodlerFixed then
				FixedCodeHolder[CodeHolderType] += 1
				TotalFixed += 1
			end
		end
	end

	print(
		"Fixed "
			.. Object:GetFullName()
			.. " and its descendants\n"
			.. TreeTab
			.. "-Time Taken: "
			.. tostring(os.time() - Time)
			.. " seconds\n"
			.. TreeTab
			.. "-Scripts Fixed: "
			.. tostring(FixedCodeHolder.Script)
			.. " Scripts\n"
			.. TreeTab
			.. "-LocalScripts Fixed: "
			.. tostring(FixedCodeHolder.LocalScript)
			.. " LocalScripts\n"
			.. TreeTab
			.. "-ModuleScripts Fixed: "
			.. tostring(FixedCodeHolder.ModuleScript)
			.. " ModuleScripts\n"
			.. TreeTab
			.. "-Total Fixed: "
			.. tostring(TotalFixed)
			.. " Scripts/LocalScripts/ModuleScripts"
	)

	ChangeHistoryService:SetWaypoint("Fixed " .. Object:GetFullName() .. " and its descendants")

	Selection:Set({
		Object,
	})

	return CreateModule
end

function UpdateModulePackage()
	CheckCodeHolderPermission()

	print("Updating Gear Module Packages")

	local Time = os.time()

	local GearModulesFolder = ReplicatedStorage:FindFirstChild("GearModulesFolder")

	if GearModulesFolder then
		GearModulesFolder:Destroy()
	end

	GearModulesFolder = Instance.new("Folder")

	GearModulesFolder.Name = "GearModulesFolder"
	GearModulesFolder.Parent = ReplicatedStorage

	require(9507732691)(GearModulesFolder)

	repeat
		task.wait()
	until GearModulesFolder:GetAttribute("Loaded") == true

	Fix(GearModulesFolder)

	print("Gear Module Packages Updated\n" .. TreeTab .. "-Time Taken: " .. tostring(os.time() - Time) .. " seconds")
end

LoadGearsButton.ClickableWhenViewportHidden = true
FixObjectButton.ClickableWhenViewportHidden = true
UpdateModulePackagesButton.ClickableWhenViewportHidden = true

LoadGearsButton.Click:Connect(function()
	print("Initiallizing")

	local GearsFolder = ServerStorage:FindFirstChild("GearsFolder")

	if GearsFolder then
		GearsFolder:Destroy()
	end

	GearsFolder = Instance.new("Folder")

	GearsFolder.Name = "GearsFolder"
	GearsFolder.Parent = ServerStorage

	Selection:Set({
		GearsFolder,
	})

	print("Fetching Gears List")

	local Gears = HttpService:JSONDecode(
		HttpService:GetAsync("https://raw.githubusercontent.com/iUnstable0/Roblox/main/Gears-Detailed.json")
	)

	print(
		"Got Gears List\n"
			.. TreeTab
			.. "-Total Gears: "
			.. tostring(#Gears.data)
			.. "\n"
			.. TreeTab
			.. "-Last Updated: "
			.. Gears["last-updated"]
	)

	local Loaded = 0

	local FixedCodeHolder = {
		Script = 0,
		LocalScript = 0,
		ModuleScript = 0,
	}

	local TotalFixed = 0

	print("Loading " .. tostring(#Gears.data) .. " Gears in " .. GearsFolder:GetFullName())

	CheckCodeHolderPermission()

	local Time = os.time()

	for Index, Gear in pairs(Gears.data) do
		coroutine.wrap(function()
			-- Safety check, https://devforum.roblox.com/t/open-source-gear-utility/1776131/34?u=iunstable0
			if string.find(Gear.name, "ROBLOX Tablet") then
				return
			end

			local Success, InsertedGear = pcall(function()
				return InsertService:LoadAsset(Gear.id)
			end)

			if not Success then
				Loaded += 1

				print(
					"Failed to load "
						.. tostring(Loaded)
						.. "/"
						.. tostring(#Gears.data)
						.. " Gears\n"
						.. TreeTab
						.. "-Gear Name: "
						.. Gear.name
						.. "\n"
						.. TreeTab
						.. "-Gear Id: "
						.. tostring(Gear.id)
				)

				return
			end

			for Index, Object in pairs(InsertedGear:GetChildren()) do
				if Object:IsA("Tool") then
					Object:SetAttribute("GEARDATA_id", Gear.id)
					Object:SetAttribute("GEARDATA_name", Gear.name)

					Object.Parent = GearsFolder
				end
			end

			InsertedGear:Destroy()

			Loaded += 1

			print(
				"Loaded "
					.. tostring(Loaded)
					.. "/"
					.. tostring(#Gears.data)
					.. " Gears\n"
					.. TreeTab
					.. "-Gear Name: "
					.. Gear.name
					.. "\n"
					.. TreeTab
					.. "-Gear Id: "
					.. tostring(Gear.id)
			)
		end)()
	end

	repeat
		task.wait()
	until Loaded >= #Gears.data

	print(
		"Loaded "
			.. tostring(#Gears.data)
			.. " Gears in "
			.. GearsFolder:GetFullName()
			.. "\n"
			.. TreeTab
			.. "-Time Taken: "
			.. tostring(os.time() - Time)
			.. " seconds"
	)

	ChangeHistoryService:SetWaypoint("Loaded " .. tostring(#Gears.data) .. " Gears in " .. GearsFolder:GetFullName())

	if Fix(GearsFolder) then
		UpdateModulePackage()
	end
end)

FixObjectButton.Click:Connect(function()
	local SelectedObject = Selection:Get()

	if #SelectedObject == 0 then
		error("Please an object to fix")
	elseif #SelectedObject > 1 then
		error("Please select only one object")
	elseif SelectedObject[1].Name == "GearUtilityPlugin" then
		error("You cannot fix this script")
	end

	if Fix(SelectedObject[1]) then
		UpdateModulePackage()
	end
end)

UpdateModulePackagesButton.Click:Connect(function()
	UpdateModulePackage()
end)

Screen Shot 2022-05-01 at 11.25.27 AM

32 Likes

Sorry I forgot to put the plugin on sale, u should be able to install it now

3 Likes

I fixed the plugin not showing in studio Plugins tab
please update it

3 Likes

this is something genius but has to be improved as this isn’t a temporary fix for most of the gears 'cause of the fact that it replacec a few lines of code, I think there should be an auto-fix mechanism for non-filtering gears.

3 Likes

wdym non-filtering gear? or did u mean gears that still use insertservice on the client side or non FE gears

2 Likes

Can you include a video of the plugin?

3 Likes

Sure but why do you need the video though?
I can record a video later I’m busy right now

2 Likes

I would like a video of the plugin so I know what it does and if its worth installing.

2 Likes

It works perfectly! I will definitely use it in my game!

2 Likes

thank you! :smiley: If you find any broken gears please tell me so I can fix it and update the plugin

1 Like

Added new script permission check so the plugin wont start until it is granted script injection permission

Video: Gear Utility Demo - YouTube

3 Likes

he means non fe gears is that possible?

@iUnstable0 there’s at least several hundred that need to be fixed because of Filtering Enabled turned on however I wouldn’t recommend fixing the insert tool and stamp tool because of well you know

1 Like

it is possible but requires a lot of work

How could a fe detecter work at all? that’s sound almost impossible

hey one little improvement you can make is where it changes connect to Connect because a lot of gears have connect instead of Connect

1 Like

That wont make any differences and instead it could cause problems

how could it cause problems also connect is deprecated

1 Like

This plugin is amazing! I am working on a project that requires the use of ROBLOX’s gears and this helped a ton. I also love that you added in the name and Id of the gear as attributes in its respective tool.

Kudos to you

3 Likes

glad that it helped your project! :slight_smile: