LocalScripts running in the workspace

Ok, here’s the code implementing this solution. Note: it turns out that you don’t even need the coroutines I was talking about.

Usage:
Runs the module:run() method on all module scripts tagged as “LocalScript” who are descendants of game.Workspace or game.Players.


StarterPlayer/StarterPlayerScripts/WorkspaceClientScripts

--[[
	WorkspaceClientScripts
	Author: radbuglet
--]]

-- /// Services ///
local CollectionService = game:GetService("CollectionService")

-- /// Constants ///
local LOCAL_SCRIPT_TAG = "LocalScript"
local APPLICABLE_ANCESTORS = { workspace, game.Players }

local MIRROR_SCRIPTS_CONTAINER_FOLDER = script
local MIRROR_SCRIPT_TEMPLATE = script.MirrorScriptTemplate

-- /// Helpers ///
local function run_for_each_tagged_instance(tag, callback)
	local instances_detected = {} -- @WARN there's a possible memory leak here because deleted instances are never cleaned up
	
	local function wrapped_callback(object)
		-- Temporary patch for double firing error detailed [here](https://devforum.roblox.com/t/double-firing-of-collectionservice-getinstanceaddedsignal-when-applying-tag-in-same-frame-that-object-is-added-to-datamodel/244235?u=radbuglet)
		if instances_detected[object] == true then return end
		instances_detected[object] = true
		
		-- Check if is descendant of applicable ancestor
		for _, ancestor in pairs(APPLICABLE_ANCESTORS) do
			if ancestor:IsAncestorOf(object) then
				callback(object)
				break
			end
		end
	end
	
	CollectionService:GetInstanceAddedSignal(tag):Connect(wrapped_callback)
	for _, object in pairs(CollectionService:GetTagged(tag)) do
		wrapped_callback(object)
	end
end

-- /// Setup ///
run_for_each_tagged_instance(LOCAL_SCRIPT_TAG, function(object)
	if not object:IsA("ModuleScript") then
		error("Objects tagged with " .. LOCAL_SCRIPT_TAG .. " must be module scripts!")
		return
	end
	
	local mirror_script = MIRROR_SCRIPT_TEMPLATE:Clone()
	mirror_script.Name = object:GetFullName()
	mirror_script.Disabled = false
	
	local master_script_value = Instance.new("ObjectValue")
	master_script_value.Name = "MasterScript"
	master_script_value.Value = object
	master_script_value.Parent = mirror_script
	
	mirror_script.Parent = MIRROR_SCRIPTS_CONTAINER_FOLDER
end)

StarterPlayer/StarterPlayerScripts/WorkspaceClientScripts/MirrorScriptTemplate (Must be Disabled!)

--[[
	WorkspaceClientScripts/MirrorScriptTemplate
	Author: radbuglet
--]]

local master_script = script.MasterScript.Value

master_script.AncestryChanged:Connect(function()
	if not game:IsAncestorOf(master_script) then
		script:Destroy()
	end
end)

require(master_script):run()

Please tell me if there are any bugs I need to fix or an easier way to fix my problem.

Thanks,
rad

2 Likes