Can't have plugin installed without receiving error 260

I have made a plugin and published it. its extremely ugly and bare-bones, but it uses RegEx and Script.Source to scour all script functions and put a comment before each one. So that way, I can automatically doc all my forgotten functions. Once published, it prompts the user that the plugin wants to do script injection, and I allowed it. And now it works perfectly

However, trying to test the game, or ANY game within studio while this plugin is installed will give an error that reads: “There was a problem receiving data, please reconnect. (Error Code: 260)” Is this a bug? I thought plugins and command lines were allowed to mess with script.sources

1 Like

If you do the same eithout your plugin does the issue still occur?

1 Like

Nope. I tested this several times with a published plugin, local plugin, and no plugin. If i have this plugin, regardless if its published or not, then i cannot test with it. Removing the plugin allows me to immediately test again

Ive made an even simpler script that just sets a TargetScript’s source from Print(“Hello world”) to “”. I published this plugin and used it locally and it WILL let me use it and test the game. So ig it isnt the fact that the script.source is being modified. Something within my real plugin must be causing problems, but what would cause an error 260 with a plugin?

I’m posting the plugin code here, in case anything sticks out:

--Made by Valentine/Swoggers
local Toolbar = plugin:CreateToolbar("FunctionDoc")
local PluginButton = Toolbar:CreateButton(
	"Doc all functions",
	"Click here to create comments above every function",
	"rbxassetid://14146206568"
)
local pattern = "(function%s+%w+%s*%([^)]*%s*%)[^end]*end)"
local LabledCheckbox = require(script.Parent.StudioWidgets.LabeledCheckbox)
local CustomTextButton = require(script.Parent.StudioWidgets.CustomTextButton)
local SearchConfigFrame = script.Parent.SearchConfig
local info = DockWidgetPluginGuiInfo.new(
	Enum.InitialDockState.Right,
	false,
	false,
	200,
	300,
	150,
	150
)
local Widget = plugin:CreateDockWidgetPluginGui("FunctionDoc",info)
Widget.Title = "Autodoc Functions"
SearchConfigFrame.Parent=Widget
--This creates all the checkboxes and buttons my guis will be using
local BeginTextButton = CustomTextButton.new("BeginButton","Begin")
BeginTextButton:GetButton().Size = UDim2.new(.7,0,.062,0)
BeginTextButton:GetButton().AnchorPoint = Vector2.new(.5,1)
BeginTextButton:GetButton().Position = UDim2.new(.5,0,1,0)
BeginTextButton:GetButton().Parent=SearchConfigFrame
local DocumentFrame = script.Parent.DocumentFrame
local SkipButton = CustomTextButton.new("SkipButton","Skip")
SkipButton:GetButton().Size = UDim2.new(.3,0,1,0)
SkipButton:GetButton().Parent=DocumentFrame.OptionButtons
local CommentButton = CustomTextButton.new("CommentButton","Comment")
CommentButton:GetButton().Size = UDim2.new(.3,0,1,0)
CommentButton:GetButton().Parent=DocumentFrame.OptionButtons
DocumentFrame.Parent = Widget
local ScriptLocationLabel = DocumentFrame.InnerFrame.ScriptLocationLabel
local CommentTextBox = DocumentFrame.InnerFrame.CommentTextBox
local CodeTextLabel = DocumentFrame.InnerFrame.CodeFrame.CodeTextLabel
local WorkspaceCheckbox = LabledCheckbox.new("wrksp","Workspace",true,false)
WorkspaceCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local PlayersCheckbox = LabledCheckbox.new("plyrs","Players",false,false)
PlayersCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local LightingCheckbox = LabledCheckbox.new("light","Lighting",false,false)
LightingCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local MaterialServiceCheckbox = LabledCheckbox.new("mtrls","MaterialService",false,false)
MaterialServiceCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local NetworkClientCheckbox = LabledCheckbox.new("ntwkclnt","NetworkClient",false,false)
NetworkClientCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local ReplicatedFirstCheckbox = LabledCheckbox.new("repfrst","ReplicatedFirst",true,false)
ReplicatedFirstCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local ReplicatedStorageCheckbox = LabledCheckbox.new("repstrg","ReplicatedStorage",true,false)
ReplicatedStorageCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local ServerScriptServiceCheckbox = LabledCheckbox.new("sss","ServerScriptService",true,false)
ServerScriptServiceCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local ServerStorageCheckbox = LabledCheckbox.new("srvrstrg","ServerStorage",true,false)
ServerStorageCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local StarterGuiCheckbox = LabledCheckbox.new("strtrplyr","StarterGui",true,false)
StarterGuiCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local StarterPackCheckbox = LabledCheckbox.new("strtrpck","StarterPack",false,false)
StarterPackCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local StarterPlayerCheckbox = LabledCheckbox.new("strtrplyr","StarterPlayer",true,false)
StarterPlayerCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local TeamsCheckbox = LabledCheckbox.new("teams","Teams",false,false)
TeamsCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local SoundServiceCheckbox = LabledCheckbox.new("sndsrvc","SoundService",false,false)
SoundServiceCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local TextChatServiceCheckbox = LabledCheckbox.new("txtchtsrv","TextChatService",false,false)
TextChatServiceCheckbox:GetFrame().Parent=SearchConfigFrame.CheckmarkList
local AllPossibleLocations ={
	{
		WorkspaceCheckbox,
		workspace
	},
	{
		PlayersCheckbox,
		game:GetService("Players")
	},
	{
		LightingCheckbox,
		game:GetService("Lighting")
	},
	{
		MaterialServiceCheckbox,
		game:GetService("MaterialService")
	},
	{
		NetworkClientCheckbox,
		game:GetService("NetworkClient")
	},
	{
		ReplicatedFirstCheckbox,
		game:GetService("ReplicatedFirst")
	},
	{
		ReplicatedStorageCheckbox,
		game:GetService("ReplicatedStorage")
	},
	{
		ServerScriptServiceCheckbox,
		game:GetService("ServerScriptService")
	},
	{
		ServerStorageCheckbox,
		game:GetService("ServerStorage")
	},
	--
	{
		StarterGuiCheckbox,
		game:GetService("StarterGui")
	},
	{
		StarterPackCheckbox,
		game:GetService("StarterPack")
	},
	{
		StarterPlayerCheckbox,
		game:GetService("StarterPlayer")
	},
	{
		TeamsCheckbox,
		game:GetService("Teams")
	},
	{
		SoundServiceCheckbox,
		game:GetService("SoundService")
	},
	{
		TextChatServiceCheckbox,
		game:GetService("TextChatService")
	}
}
local AllScriptsArray={}
local SkipButtonConnection,CommentButtonConnection
--This filters for all scripts and local scripts and returns an array of them
function FilterForScripts(ContaminatedArray)
	local TempArray={}
	for __,element in ContaminatedArray do
		if element:IsA("Script") or element:IsA("LocalScript") then
			table.insert(TempArray,element)
		end
	end 
	return TempArray
end
--this returns an array of the start of the functions and the content of the function using regex
function FindAllFunctions(Script)
	local functions = {}
	local functionStart = 0
	local depth = 0
	local currentFunction = ""
	for lineNumber, line in Script:gmatch("()([^\n]*)\n?") do
		if line:match("^%s*function%s+%w+%s*%([^)]*%s*%)") then
			functionStart = lineNumber
			currentFunction = line .. "\n"
			depth = depth + 1
		elseif depth > 0 then
			currentFunction = currentFunction .. line .. "\n"
			if line:match("end") then
				depth = depth - 1
				if depth == 0 then
					table.insert(functions, { start = functionStart, content = currentFunction })
					currentFunction = ""
				end
			end
		end
	end
	print("functions: ",functions)
	local functionsMissingComments = {}
	for i = #functions, 1, -1 do
		local funcContent = functions[i].content
		-- Checking if the function lacks comments/documentation
		if not funcContent:match("^%s*%-%-[^[]*\n") and not funcContent:match("^%s*%-%-%[%[[^%[%]]*\]%][^[]*\n") then
			table.insert(functionsMissingComments, functions[i]) -- Insert function content missing comments
		end
	end
	print("functionMissingComments: ",functionsMissingComments)
	return functionsMissingComments
end
--this goes through the array of all locations and grabs all the scripts within and sends that through the FindAllFunctions
function FindAllScripts()
	for __,element in AllPossibleLocations do
		if element[1]:GetValue() then
			AllScriptsArray[element[2].Name] = {}
			local AllScripts = FilterForScripts(element[2]:GetDescendants())
			for __,Script in AllScripts do
				AllScriptsArray[element[2].Name][Script] = FindAllFunctions(Script.Source)
			end
		end
	end
	SearchConfigFrame.Visible=false
	DocumentFrame.Visible=true
	for ScriptLocation,Script in AllScriptsArray do
		for ScriptInst,Element in Script do
			for __,FunctionTable in Element do
				ScriptLocationLabel.Text = ScriptLocation.."."..ScriptInst.Parent.Name.."."..ScriptInst.Name
				CodeTextLabel.Text =FunctionTable.content
				CodeTextLabel.Size = UDim2.new(0,CodeTextLabel.TextBounds.X,0,CodeTextLabel.TextBounds.Y)
				CodeTextLabel.Parent.CanvasSize = UDim2.new(0,CodeTextLabel.TextBounds.X,0,CodeTextLabel.TextBounds.Y)
				local ProceedFlag = true
				SkipButtonConnection = SkipButton:GetButton().Activated:Connect(function()
					ProceedFlag=false
				end)
				CommentButtonConnection = CommentButton:GetButton().Activated:Connect(function()
					if CommentTextBox.Text ~="" then
						local funcStart = FunctionTable.start
						local funcContent = FunctionTable.content
						-- Adding multiline comment for documentation to functions missing comments
						local commentedFunction = "--[[\n"..CommentTextBox.Text .."\n]]--\n".. funcContent
						ScriptInst.Source = ScriptInst.Source:sub(1, funcStart - 1) .. commentedFunction .. ScriptInst.Source:sub(funcStart + #funcContent)
						ProceedFlag=false
					end
				end)
				while ProceedFlag do
					wait()
				end
				CommentButtonConnection:Disconnect()
				SkipButtonConnection:Disconnect()
			end
		end
	end
	SearchConfigFrame.Visible=true
	DocumentFrame.Visible=false
end
--This toggles the gui
function PromptSearchGui()
	print("pressed")
	Widget.Enabled = not Widget.Enabled
	if SkipButtonConnection then
		SkipButtonConnection:Disconnect()
	end
	if CommentButtonConnection then
		CommentButtonConnection:Disconnect()
	end
	SearchConfigFrame.Visible=true
	DocumentFrame.Visible=false
end
PluginButton.Click:connect(PromptSearchGui)
BeginTextButton:GetButton().MouseButton1Click:Connect(FindAllScripts)

Besides the regex, I feel like this is a basic script. This script is within a folder beside gui frames and module scripts that create more guis. (The gui scripts used are the StudioWidgets provided by roblox)

1 Like